【问题标题】:objective c - block retain cycle目标 c - 块保留周期
【发布时间】:2014-02-19 13:01:09
【问题描述】:

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

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

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

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

foo3 会创建一个保留循环吗?

【问题讨论】:

  • 您是否收到编译器警告?

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


【解决方案1】:

不,没有保留周期。

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

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

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

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

【讨论】:

  • 很好的解释。在马里奥的问题中,在调用“foo1withBlock”之前使用指向“self”的“__weak”指针有什么真正的好处吗?例如,“self”可以是发起网络请求的视图控制器。如果你不想等待它完成,你可能想离开,让它释放并留下对 self 的 nil 引用的块?
  • @SpinalTapFan11 确实存在您想要使用“弱自我”与“强烈捕捉自我”的场景。使用弱指针还是强捕获指针的决定不是“好处”,而是取决于您的用例和您想要完成的任务:请参见此处:stackoverflow.com/questions/21987067/…
【解决方案2】:

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

【讨论】:

  • 我不确定您所说的“您没有在这里调用彼此的方法”是什么意思。如果代码正在这样做,您将获得的不仅仅是一个保留周期...
【解决方案3】:
- (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];
   }]; 
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-12-07
    • 1970-01-01
    • 1970-01-01
    • 2015-08-20
    • 2013-09-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多