52个有效方法(38) - 为常用的块类型创建typedef

每个块都具备其“固有类型”(inherent type),因而可将其赋值给适当类型的变量。这个类型由块所接受的参数及其返回值组成。

块类型的语法结构如下:

return_type (^block_name)(parameters)

如果想把块赋给变量,则需注意其类型。变量类型及相关赋值语句如下:

int someInt = 0;
int (^variableName)(BOOL flag, int value) = ^(BOOL flag, int value)
{
    return someInt;
};
typedef关键字用于给类型起个易读的别名:
typedef int (^EOCSomeBlock)(BOOL flag, int value);

声明变量时,要把名称放在类型中间,并在前面加上“^”符号,而定义新类型时也得这么做。与定义其他变量时一样,变量类型在左边,变量名在右边。

EOCSomeBlock block = ^(BOOL flag, int value)
{
    return someInt;
};
  • 使用在函数参数时作用更加明显,易于理解。定义方法参数所用的块类型语法,又和定义变量时不同。
typedef void (^EOCCompletionHandler)(NSData *data, NSError *error);
- (void)startWithCompletionHandler:(EOCCompletionHandler)completion;
  • 使用typedef关键字在重构块的类型签名时会很方便。比方说,要给原来的completion handler块再加一个参数,用以表示完成任务所花的时间,那么只需修改类型定义语句即可:
typedef void (^EOCCompletionHandler)(NSData *data, NSTimeInterval duration, NSError *error);
  • 最好在使用块类型的类中定义这些typedef,而且还应该把这个类的名字加在由typedef所定义的新类型名前面,这样可以阐明块的用途。还可以用typedef给同一个块签名类型创建数个别名。Mac OS X与iOS的Accounts框架就是个例子。在该框架中可以找打下面这两个类型定义语句:
typedef void(^ACAccountStoreSaveCompletionHandler)(BOOL success, NSError *error);
typedef void(^ACAccountStoreRemoveCompletionHandler)(BOOL success, NSError *error);
typedef void(^ACAccountStoreRequestAccessCompletionHandler)(BOOL granted, NSError *error);
  • 如果有好几个类都要执行相似但各有区别的异步任务,而这几个类又不能放入同一个继承体系,那么,每个类就应该有自己的completion handler类型。这几个completion handler的签名也许完全相同,但最好还是在每个类里都各自定义一个别名,而不要共用同一个名称。反之,若这些类能纳入同一个继承中,则应该将类型定义的语句放在超类中,以供各子类使用。
要点
  1. 以typedef重新定义块类型,可令块变量用起来更加简单。

  2. 定义新类型时应遵循现有的命名习惯,勿使用其名称与别的类型相冲突。

  3. 不妨为同一个块签名定义多个类型别名。如果要重构的代码使用了块类型的某个别名,那么只需要修改相应typedef中的块签名即可,无需改动其他typedef。

你可能感兴趣的:(52个有效方法(38) - 为常用的块类型创建typedef)