我想从内部递归调用一个块。在 obj-c 对象中,我们可以使用“self”,是否有类似的东西可以从自身内部引用块实例?
问问题
2671 次
4 回答
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
是为了确保块不会捕获对自身的强引用,这会导致内存泄漏。
于 2011-01-28T03:43:04.040 回答
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 限定符,以便块不会捕获块引用的尚未分配的值。
- 如果您正在执行手动内存管理,则需要自己自动释放复制的块。
于 2012-05-12T03:06:54.710 回答
6
您必须将块变量声明为__block
:
typedef void (^MyBlock)(id);
__block MyBlock block = ^(id param) {
NSLog(@"%@", param);
block(param);
};
于 2011-01-28T03:43:46.650 回答
3
没有self
for 块(还)。您可以像这样构建一个(假设为 ARC):
__block void (__weak ^blockSelf)(void);
void (^block)(void) = [^{
// Use blockSelf here
} copy];
blockSelf = block;
// Use block here
__block
是必需的,因此我们可以blockSelf
在创建块后设置块。这__weak
是必需的,因为否则该块将持有对自身的强引用,这将导致强引用循环并因此导致内存泄漏。copy
需要确保将块复制到堆中。对于较新的编译器版本,这可能是不必要的,但它不会造成任何伤害。
于 2013-06-21T12:33:53.530 回答