我不知道对于 objective-c 中的文字范围,我应该避免使用哪些块模式


苹果

的文档中说: 块文本(即 ^{ ... })是表示块的堆栈本地数据结构的地址。因此,堆栈本地数据结构的作用域是封闭复合语句,因此应避免使用以下示例中显示的模式:

void dontDoThis() {
    void (^blockArray[3])(void);  // an array of 3 block references
    for (int i = 0; i < 3; ++i) {
        blockArray[i] = ^{ printf("hello, %dn", i); };
        // WRONG: The block literal scope is the "for" loop.
    }
    //for example I invoke the block here
    blockArray[1]();
  }

void dontDoThisEither() {
    void (^block)(void);
    int i = random():
    if (i > 1000) {
        block = ^{ printf("got i at: %dn", i); };
        // WRONG: The block literal scope is the "then" clause.
    }
    // ...
  }

我不知道我应该避免什么模式。似乎我可以调用与块定义具有相同文字范围的块,例如在"if"或"for"语句后面。你能帮我解释一下吗?

这是链接 https://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/Blocks/Articles/bxUsing.html#//apple_ref/doc/uid/TP40007502-CH5-SW1

我认为对指针的类比如下。

void foo() {
  int *block = NULL;
  {
    int a;
    block = &a;
  }
  // `block`, even though defined here, points to
  // an invalid memory address.
}
通常,块文字

本身仅存在于它定义的块中,因此当离开该块时,文字消失(就像上面示例中的变量a所做的那样),并且您留下了一个悬而未决的指针。

因此,通常会将块复制到堆中以供将来使用。非 ARC 代码使用block_copy和朋友。复制到堆中还会捕获块使用的所有相关变量(这可能会创建保留周期)。

在实践中,所有这些都通过使用 ARC、属性和类而完全避免。在类中定义一个 copy 属性,然后只为其分配块。如果你让编译器生成getter/setter,你的块文字将自动复制到堆中。

@interface Bla : NSObject
@property (nonatomic, copy) void (^blockProperty)(int i);
@endf
...
Bla *bla = [[Bla alloc] init];
{
  bla.blockProperty = ^(int i) { printf("%d", i); };
}
// bla.blockProperty now points to a heap copy of the block literal from above,
// so it's not dangling.

我正在阅读Apple关于块的文档,并在这方面做了更多的研究。在我看来,使用 ARC 的第二个示例代码完全没问题。我没有尝试第一个例子。接受答案中的一般想法是正确的。但是,使用 ARC 时,当您将文本块 (NSStackBlock) 分配给局部变量时,该块将被复制到堆中,如果您检查该块,您会发现它确实是一个 NSMallocBlock。我还参考了这个关于这个主题的博客 https://www.cocoawithlove.com/2009/10/how-blocks-are-implemented-and.html

最新更新