有目的地创建保留周期(没有GC的目标C)

时间:2013-05-02 16:49:26

标签: objective-c memory-management automatic-ref-counting retain-cycle

是否存在故意创建保留周期以防止重新分配,然后在以后清理它的情况,是问题的最佳解决方案?

如果是这样,Cocoa Touch或NextStep框架中是否有这样的例子?

我打算将此问题专门用于使用ARC的Objective C,因为使用GC或其他GC语言的目标C可能表现不同。

2 个答案:

答案 0 :(得分:7)

不确定。它实际上并非罕见,尽管你可能没有意识到这一点。

例如,假设我的控制器正在发出网络请求,而我确实需要确保我处理响应,即使用户已离开该控制器。

我可能会这样做:

- (void)doNetworkThing {
    __block MyController *blockSelf = self;

    NSURLRequest *request = // some request
    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:
      ^(NSURLResponse *response, NSData *data, NSError *error) {
          // Handle the response here
          [blockSelf doThingWithResponse:response];
      }];
}

这引入了一个简单的保留周期,其中self通过将自身赋值给强指针blockSelf而使其自身保留。在blockSelf超出范围之前,不会取消分配自我。

请注意,在这种情况下,您通常会使用弱指针。但是如果你真的需要控制器来处理它,那么使用强指针也可以。处理程序块一旦被释放,它对blockSelf的引用就会消失。由于对blockSelf的堆栈引用也已消失,因此如果没有其他人继续使用它,则会自行释放。

基本上,blockSelf引起了临时保留周期,这有助于确保在请求完成之前不会发生重新分配。因为当__block变量超出范围时,ARC会自动清除保留计数,因此它看起来不像保留周期。但尽管如此,那就是它。

答案 1 :(得分:1)

当然,有几个。最值得注意的是NSURLConnection使用其委托生成一个保留循环,以确保委托在连接完成之前不会消失。理想情况下,NSTimer会生成一个带有目标的保留循环。遗憾的是,这会导致重复计时器出现问题(请参阅RNTimer以了解解决此问题的多次尝试之一。)

一般来说,如果委托对象与其委托相比具有非常短的生命周期,则保留其委托以创建有益的保留循环是很自然的。

对于某些类型的“自我保留”物体来说,这种情况并不常见,但仍然存在。例如,如果您有一个想要创建的对象并执行某些操作,然后自行销毁,那么自我保留可以解决该问题。通常最好避免这种情况并让调用者保留对象,但它仍然有其用途(我已经将它用于日志记录和其他我想要发射的非关键操作)。

也就是说,在我的代码中故意创建带有块的短期保留循环以确保调用对象在块完成之前不会消失的情况并不少见。