Blocks Blocks
Swift 里的闭包(closure)在 Objective-C 里就是区块(Block)。如果你觉得闭包的语法很烂我只能说,年轻人,那是你还年轻,不信我们先看一个 Swift 的闭包:
let universalGreeting = {
print("Bah-weep-graaaaagnah wheep nini bong")
}
universalGreeting()
要在 Objective-C 实现上面这段代码的话,就要这么写:
void (^printUniversalGreeting)(void) = ^{
NSLog(@"Bah-weep-graaaaagnah wheep nini bong");
};
printUniversalGreeting();
先来看看里面的关键字都是什么意思:
- void: 区块不返回任何值
- (^printUniversalGreeting): 把区块放进一个叫 printUniversalGreeting 的变量
- (void): 区块不需要传入参数
- = ^{ ... }: 区块的内容
根据上面的内容,可以对这段代码做一些修改:
NSString* (^printUniversalGreeting)(void) = ^{
return @"Bah-weep-graaaaagnah wheep nini bong";
};
我们把最前面的 void 去掉之后,这段代码就变得稍微复杂一些了。
这就表示了你想要这个区块有返回值。由于这个区块本身被声明为是字符串类型,所以还要一个字符串参数:
NSString* (^printUniversalGreeting)(NSString *) = ...
这个 NSString 的参数是必须要有的,因为这个变量本身就是 NSString 类型。
那如果想写可选参数呢?
就可以像下面这段代码一样,把参数名写在 ^ 和 { 之间:
^(NSString *name) {
完整的代码可以参考下面的这一段:
NSString* (^printUniversalGreeting)(NSString *) = ^(NSString *name) {
return [NSString stringWithFormat:@"Live long and prosper, %@.",
name];
};
这里我们再来解释一下这些概念:
- NSString*: 区块会返回一个字符串
- (^printUniversalGreeting):. 区块的名字是 printUniversalGreeting
- (NSString *): 区块必须有一个 NSString 类型的参数
- = ^: 确定这个把区块传回来的值赋值给该变量
- (NSString *name):这个区块的可选字符串参数
如果你还是对这一堆括号和尖角符号不是很清楚的话,我们可以看一下下面这段代码:
// declare the variable 声明变量
NSString* (^printUniversalGreeting)(NSString *);
// assign it a block to run 运行区块
printUniversalGreeting = ^(NSString *name) {
return [NSString stringWithFormat:@"Live long and prosper, %@.",
name];
};
// now run it and print the result 打印结果
NSLog(@"%@", printUniversalGreeting(@"Jim"));
// assign a different block to run 运行一个别的区块
printUniversalGreeting = ^(NSString *name) {
return [NSString stringWithFormat:@"Nanu Nanu, %@!", name];
};
// now run it again 再打印一次结果
NSLog(@"%@", printUniversalGreeting(@"Jim"));
这个语法看起来就不太友好,但所幸的是除了创建区块,这个语法并不常用。
在编程的过程里,你会发现可能会要用到 typedef 来简化代码,比如像这个样子:
typedef NSString* (^MyBlock)(NSString*);
typedef 意思是「给区块一个昵称」,上面这段代码表示了「创建一个叫 MyBlock 的区块,它必须有一个 NSString 的参数,并且返回一个NSString 值」。
也可以像下面这样写,它们最后的运行结果是一样的:
MyBlock printUniversalGreeting = ^(NSString *name) {
return [NSString stringWithFormat:@"Live long and prosper, %@.",
name];
};