不知道你想如何解释这件事。这是我的尝试:
块是一段代码。当您使用创建块时^{}
,该代码可以存储在变量中。在您的情况下(在大多数情况下),它会立即作为参数传递给方法,就像任何其他值一样。此示例块声明了 1 个参数,在执行代码时必须指定其值。变量object_in
将包含一些对象,您可以在代码块中使用它。
[array each:^(id object_in) {
NSLog(@"object: %@", object_in);
}];
在方法内部,代码存储在参数变量中,根据block
您的情况命名。现在您要执行代码。您可以通过将实际值列表作为块参数附加括号来实现。现在object_out
包含一些实际值,因此它将被传递给object_in
.
- (NSArray *)each:(void (^)(id))block {
for (id object_out in self) {
block(object_out); // executes the code of block with given argument
}
return self;
}
现在,您的NSLog
语句将使用数组中的每个对象执行。
它与函数指针非常相似。如果您对此有所了解,可能会更容易,如果不知道,请不要为此烦恼:)
因此,您可以通过参数将值传递给块,但还有第二种方法可以将值放入块中。它是关于捕获局部变量,但在您的示例中未使用。如果您或其他任何人希望我解释它,请随时发表评论。
编辑:所以这里是捕获变量的简单解释。包含在其中的每一段代码{}
都是作用域,因此块也是一个作用域。范围是嵌套的,其中创建的局部变量仅在控制流离开范围之前有效。子作用域可以使用来自父作用域的变量。
下面的示例代码迭代两个数组,一个是for-in
循环,第二个-each:
是问题中的方法。作为参数传递的块现在略有不同——它使用来自父作用域的一个变量(实际上它来自祖父作用域)。为什么这个块不同?该方法-each:
将被执行多次,每次都string
包含不同的值。换句话说,将创建 3 个块实例,每个实例都有自己的string
值。
NSArray *strings = @[ @"A", @"B", @"C" ];
NSArray *numbers = @[ @1, @2, @3 ];
NSString *string = nil; // doing this to be more obvious
for (string in strings) {
// string is simple local variable
[numbers each:^(id number) {
// number is argument
NSLog(@"argument: %@, captured: %@", number, string);
}];
}
输出:
argument: 1, captured: A
argument: 2, captured: A
argument: 3, captured: A
argument: 1, captured: B
argument: 2, captured: B
argument: 3, captured: B
argument: 1, captured: C
argument: 2, captured: C
argument: 3, captured: C
所以我们有代码,这对所有 3 个实例都是通用的,并且每个实例都有一些(可以)不同的变量。如果这让您想起类/对象关系,那么您是对的。
每次调用块的参数都不同(如前面的代码示例所示),并且每个实例的捕获变量也不同。每次^{
执行带有块定义 ( ) 的行时都会创建新实例。