有没有一种情况是故意创建一个保留周期来防止重新分配,然后再清理它,这是解决问题的最佳方法吗?
如果是这样,在 Cocoa Touch 或 NextStep 框架中是否有这样的例子?
我打算让这个问题专门针对带有 ARC 的 Objective C,因为带有 GC 的 Objective C 或其他带有 GC 的语言可能表现不同。
有没有一种情况是故意创建一个保留周期来防止重新分配,然后再清理它,这是解决问题的最佳方法吗?
如果是这样,在 Cocoa Touch 或 NextStep 框架中是否有这样的例子?
我打算让这个问题专门针对带有 ARC 的 Objective C,因为带有 GC 的 Objective C 或其他带有 GC 的语言可能表现不同。
当然。这实际上并不少见,尽管您可能没有意识到。
例如,假设我的控制器正在发出网络请求,我确实需要确保我处理响应,即使用户已经离开该控制器。
我可能会做这样的事情:
- (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
超出范围之前,self 不会被释放。
请注意,在这种情况下,您通常会使用弱指针。但是如果你真的需要控制器来处理它,使用强指针也可以。一旦处理程序块被释放,它的引用blockSelf
就会消失。由于对堆栈的引用blockSelf
也消失了,如果没有其他人持有它,那么 self 将被释放。
所以基本上,blockSelf
导致了一个临时保留周期,这有助于确保在请求完成之前不会发生释放。因为当 __block 变量超出范围时 ARC 会自动清理保留计数,所以它看起来不像保留循环。但无论如何,就是这样。
当然,有几个。最值得注意的是NSURLConnection
,它的委托生成一个保留循环,以确保委托在连接完成之前不能离开。不太理想的是,NSTimer
生成一个带有目标的保留循环。不幸的是,这会导致重复计时器出现问题(有关解决此问题的众多尝试之一,请参阅RNTimer )。
一般来说,如果委托对象的生命周期与其委托相比非常短,那么它很自然地保留其委托以创建有益的保留循环。
对于某些类型的对象“自我保留”,这种情况不太常见,但仍然存在。例如,如果您想要创建一个对象并执行一些操作,然后自行销毁,那么 self retain 可以解决该问题。通常最好避免这种情况并让调用者保留该对象,但它仍然有它的用途(我已将它用于日志记录和其他我想触发后忘记的非关键操作)。
也就是说,在我的代码中,故意用块创建短暂的保留循环以确保调用对象在块完成之前不会消失,这种情况并不少见。