目标c - 阻止保留周期

时间:2014-02-19 13:01:10

标签: ios iphone objective-c objective-c-blocks

我有一个块保留周期问题,
假设我有以下3种方法,都在一个类中。

- (void)foo1WithBlock:(void (^)(BOOL success))completion
   // do something...
   completion(YES)
}  

- (void)foo2 {
   // do something...
}  

- (void)foo3 {
   [self foo1WithBlock:^(BOOL success) {
       [self foo2];
   }]; 
}

foo3会创建一个保留周期吗?

3 个答案:

答案 0 :(得分:9)

不,没有保留周期。

但是,self捕获。这意味着, self 导入到复合语句的词法范围内(由块执行的语句)。这涉及制作“外部”变量self的副本,该变量创建块的变量self

可以复制释放block_copy操作会将捕获的变量“移动”到堆上。它们存在于那里,直到块通过block_release操作被销毁。编译器/运行时提供内部函数来复制和释放块,并在需要时执行它们。例如,如果通过dispatch_async()异步执行块,则必须首先复制块,然后在块完成后再次释放。这些block_copyblock_release操作由编译器插入并由运行时执行,因此请不要担心。

如果要复制该块,则会保留效果self,并在块被释放时再次释放 - 这在块完成时会发生。

实际上,这可以保证块中的self和块的生命周期内的self是有效的(也就是说,它不会被释放),无论是同步调用还是异步调用。当块已异步执行时,块已被复制,因此保留了self。并且self将仅在块完成之后再次释放。这也意味着,块“将”延长{{1}}的生命期,直到块完成为止。

答案 1 :(得分:0)

不,没有保留周期......因为你没有在这里调用其他方法。

答案 2 :(得分:-1)

- (void)foo3 {
   [self foo1WithBlock:^(BOOL success) {
       [self foo2];
   }]; 
}

在这种情况下,如果你不理解传递给foo1WithBlock的块的生命周期:使用这个习惯用法来防止块不适当地延长self的生命周期可能是个好主意。

- (void)foo3 {
   __weak ParentType *wself = self;  //create a weak reference (weak automatically gets set to nil on dealloc)
   [self foo1WithBlock:^(BOOL success) {
       ParentType *self = wself;  //create a local strong reference for the life of the block.
       [self foo2];
   }]; 
}

如果你正在使用cocoapods,libextobjc有一个EXTScope,它为此提供了帮助宏:

- (void)foo3 {
   @weakify(self);
   [self foo1WithBlock:^(BOOL success) {
       @strongify(self);
       [self foo2];
   }]; 
}