是否有块的SELF指针?

时间:2011-01-28 03:37:25

标签: objective-c cocoa objective-c-blocks

我想以递归方式从内部调用一个块。在一个obj-c对象中,我们使用“self”,是否有这样的东西从内部引用块实例?

4 个答案:

答案 0 :(得分:27)

有趣的故事!块实际上是Objective-C对象。也就是说,没有公开的API来获取块的self指针。

但是,如果在使用块之前声明块,则可以递归使用它们。在非垃圾收集环境中,您可以执行以下操作:

__weak __block int (^block_self)(int);
int (^fibonacci)(int) = [^(int n) {
    if (n < 2) { return 1; }
    return block_self(n - 1) + block_self(n - 2);
} copy];

block_self = fibonacci;

__block修饰符应用于block_self 必要,否则,block_self内的fibonacci引用会在之前引用它它被分配(在第一次递归调用时崩溃你的程序)。 __weak是为了确保块不会捕获对自身的强引用,这会导致内存泄漏。

答案 1 :(得分:14)

以下递归块代码将使用ARC,GC或手动内存管理进行编译和运行,而不会发生崩溃,泄漏或发出警告(分析器或常规):

typedef void (^CountdownBlock)(int currentValue);

- (CountdownBlock) makeRecursiveBlock
{
    CountdownBlock aBlock;
    __block __unsafe_unretained CountdownBlock aBlock_recursive;
    aBlock_recursive = aBlock = [^(int currentValue)
    {
        if(currentValue >= 0)
        {
            NSLog(@"Current value = %d", currentValue);
            aBlock_recursive(currentValue-1);
        }
    } copy];
#if !__has_feature(objc_arc)
    [aBlock autorelease];
#endif

    return aBlock;
}

- (void) callRecursiveBlock
{
    CountdownBlock aBlock = [self makeRecursiveBlock];

    // You don't need to dispatch; I'm doing this to demonstrate
    // calling from beyond the current autorelease pool.
    dispatch_async(dispatch_get_main_queue(), ^
                   {
                       aBlock(10);
                   });
}

重要注意事项:

  • 您必须手动将块复制到堆中,否则当您从另一个上下文中调用它时,它会尝试访问不存在的堆栈(ARC通常会为您执行此操作,但并非在所有情况下都这样做。更好地保护它安全)。
  • 您需要两个引用:一个用于保存对块的强引用,另一个用于保存用于调用递归块的弱引用(从技术上讲,这仅适用于ARC)。
  • 必须使用__block限定符,以便块不捕获块引用的尚未分配的值。
  • 如果您正在进行手动内存管理,则需要自行自动发布复制的块。

答案 2 :(得分:6)

您必须将块变量声明为__block

typedef void (^MyBlock)(id);

__block MyBlock block = ^(id param) {
  NSLog(@"%@", param);
  block(param);
};

答案 3 :(得分:3)

块(还)没有self。您可以构建一个这样的(假设ARC):

__block void (__weak ^blockSelf)(void);
void (^block)(void) = [^{
        // Use blockSelf here
} copy];
blockSelf = block;
    // Use block here

需要__block,因此我们可以在创建块后将blockSelf设置为块。需要__weak,否则块将保持对自身的强引用,这将导致强引用周期并因此导致内存泄漏。需要copy以确保将块复制到堆中。对于较新的编译器版本,这可能是不必要的,但它不会造成任何伤害。