第三十八条 为常用的块类型创建typedef

2017/9/4 posted in  第六章 块与GCD

我们在定义一个块时,语法是这样的:

int^(variableName)(BOOL flag,int value) = ^(BOOL flag, int value){
    //Implemention
    return someInt;
}

此块接受两个类型分别为BOOLint的参数,并返回类型为int的值。并且把它赋给了一个变量。

与其他类型的变量不同,在定义块变量时,要把变量名放在类型之中,而不要放在右侧。这种语法非常难记,也非常难读。鉴于此,我们应该为常用的块类型起个别名,尤其是打算把代码发布成API供他人使用时,更应这样做。开发者可以起个更为易读的名字来表示块的用途,而把块的类型隐藏在其后面。例如:

//定义
typedef int(^EOCSomeBlock)(BOOL flag, int value);

声明变量时,要把名称放在类型中间,并在前面加上“^”符号,而定义新类型时也得这么做。上面这条语句向系统中新增了一个名为EOCSomeBlock的类型。此后,不用再以复杂的块类型来创建变量了,直接使用新类型即可:

EOCSomeBlock block = ^(BOOL flag, int value){
    // Implementation
};

这次代码读起来就顺畅多了:与定义其他变量时一样,变量类型在左边,变量名在右边。

我们可以利用这个将使用块的API做的简单易用些,例如:

-(void)startWithCompletionHandler:
            (void(^)(NSData *data, NSError *error))completion;

上面代码接受了一个块作为参数,所以我们可以用上面定义块的方法来改写它:

typedef void(^EOCCompletionHandler)(NSData *data, NSError *error);

-(void)startWithCompletionHandler: (EOCCompletionHandler)completion;

现在参数看上去就简单多了,而且易于理解。

我们在定义块的时候要注意,最好在使用块类型的类中定义这些typedef,而且还应该把这个类的名字加在由typedef所定义的新类型名前面,这样可以阐明块的用途。还可以用typedef给同一个块签名类型创建数个别名。在这件事上,多多益善。因为,开发者看到类型的别名以及签名中的参数之后,可以很容易的理解类型的用途。

与此相似,如果有好几个类都要执行相似但各有区别的异步任务,而这几个类又不 能放人同一个继承体系,那么,每个类就应该有自己的completion handler类型。这几个completion handler的签名也许完全相同,但最好还是在每个类里都各自定义一个别名,而不 要共用同一个名称。反之,若这些类能纳人同一个继承中,则应该将类型定义语句放在超类中,以供各子类使用。

要点

  • typedef重新定义块类型,可令块变量用起来更加简单。
  • 定义新类型时应遵从现有的命名习惯,勿使其名称与别的类型相冲突。
  • 不妨为同一个块签名定义多个类型别名。如果要重构的代码使用了块类型的某个别名,那么只需修改相应typedef中的块签名即可,无须改动其他typedef