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];
};

results matching ""

    No results matching ""