我想以递归方式从内部调用一个块。在一个obj-c对象中,我们使用“self”,是否有这样的东西从内部引用块实例?
答案 0 :(得分:27)
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);
});
}
重要注意事项:
答案 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
以确保将块复制到堆中。对于较新的编译器版本,这可能是不必要的,但它不会造成任何伤害。