-1

嗨,我正在使用 Objective-c 中的 Blocks。我刚刚学习了语法,以及如何编写块。但我不明白执行流程。我用谷歌搜索了它的执行流程,我找不到。

我使用了以下代码:

@interface NSArray (Extended)
- (NSArray *)each:(void (^)(id))block;
@end

@implementation NSArray (Extended)
- (NSArray *)each:(void (^)(id object))block {
for(id mObject in self)
    block(mObject);
return self;
}
@end

int main (int argc, const char * argv[]) {
@autoreleasepool {

  NSArray *array = [NSArray arrayWithObjects:@"Number one", @"Number two", nil];
  [array each:^(id object) {
     NSLog(@"obj: %@", object);
  }];

}
return 0;
}

谁能解释objective-c中块的执行流程是什么?

4

3 回答 3

5

当然。

  • main() 被调用

  • anarray被分配包含两个字符串

  • 在数组上调用该each:方法,传递一个将单个对象作为参数的块

  • 该方法使用循环each:遍历数组中的所有对象for()

    • 传递给each:方法的块为每个对象调用一次,对象是块的参数

    • 块记录描述对象的一行


块在编译时捕获代码并在运行时捕获状态。在这种情况下,块没有捕获任何状态。该块就像一个简单的 C 函数,每次调用时只打印一个日志行。

于 2013-05-03T16:26:50.513 回答
3

不知道你想如何解释这件事。这是我的尝试:

块是一段代码。当您使用创建块时^{},该代码可以存储在变量中。在您的情况下(在大多数情况下),它会立即作为参数传递给方法,就像任何其他值一样。此示例块声明了 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 个实例都是通用的,并且每个实例都有一些(可以)不同的变量。如果这让您想起类/对象关系,那么您是对的。

每次调用块的参数都不同(如前面的代码示例所示),并且每个实例的捕获变量也不同。每次^{执行带有块定义 ( ) 的行时都会创建新实例。

于 2013-05-03T17:17:51.147 回答
1

从文档:

块对象是 C 级语法和运行时特性。它们类似于标准 C 函数,但除了可执行代码之外,它们还可能包含与自动(堆栈)或托管(堆)内存的变量绑定。因此,一个块可以维护一组状态(数据),它可以用来在执行时影响行为。

如需进一步说明,请查看此链接

于 2013-05-03T09:44:56.460 回答