ARC、块和保留周期
使用 ARC 开发面向 4.0 和 5.0 的 iOS 项目。
遇到与块、ARC 和从块外部引用对象相关的问题。下面是一些代码:
__block AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[operation setCompletionBlock:^ {
if ([operation isCancelled]) {
return;
}
... do stuff ...
operation = nil;
}];
在这种情况下,编译器会发出警告,指出在块中使用“操作”将导致保留周期。在 ARC 下,__block 现在保留该变量。
如果我添加 __unsafe_unretained,编译器会立即释放该对象,所以显然这是行不通的。
我的目标是 4.0,所以我不能使用 __weak。
我尝试做这样的事情:
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
__block __unsafe_unretained AFHTTPRequestOperation *weakOperation = operation;
但是虽然weakOperation不为零,但在块内时它的任何属性都不会被填充。
考虑到上面列出的项目限制,处理这种情况的最佳方法是什么?
Working on an iOS project that targets 4.0 and 5.0, using ARC.
Running into an issue related to blocks, ARC and referencing an object from outside the block. Here's some code:
__block AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[operation setCompletionBlock:^ {
if ([operation isCancelled]) {
return;
}
... do stuff ...
operation = nil;
}];
In this case, the compiler gives a warning that using 'operation' in the block is going to lead to a retain cycle. Under ARC, __block now retains the variable.
If I add __unsafe_unretained, the compiler releases the object immediately, so obviously that won't work.
I'm targeting 4.0 so I can't use __weak.
I tried doing something like this:
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
__block __unsafe_unretained AFHTTPRequestOperation *weakOperation = operation;
but while weakOperation isn't nil, none of it's properties are populated when inside the block.
What's the best way to handle this situation given the project constraints listed above?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
假设进度有保证,保留周期可能正是您想要的。您在块末尾显式中断保留循环,因此它不是永久保留循环:调用该块时,循环就会被破坏。
不过,如果您有其他东西来保持操作,您可以将引用存储到
__weak
或__unsafe_unretained
变量中,然后在块中使用它。不需要__block
限定变量,除非由于某种原因需要在块期间更改变量的绑定;由于您不再需要中断保留周期,因此您不需要为弱变量分配任何内容。Assuming progress guarantees, a retain cycle might be exactly what you want. You explicitly break the retain cycle at the end of the block, so it's not a permanent retain cycle: when the block is called, the cycle is broken.
If you have something else keeping the operation around, though, you can store a reference into either a
__weak
or__unsafe_unretained
variable and then use that from within your block. There's no need to__block
-qualify the variable unless you for some reason need to change the variable's binding during the block; since you don't have a retain cycle to break any more, you shouldn't need to assign anything to the weak variable.这似乎是 Conrad Stoll 在 中描述的问题块、操作和保留周期,但他的文章遗漏了一些重要的点:
__block
看起来像 Apple 推荐的避免对捕获变量进行强引用的方法MRC 模式但在 ARC 模式下完全不需要。这种情况下,ARC模式下完全没有必要;在 MRC 模式下也没有必要,尽管轻量级解决方法更为冗长:void * unretainedOperation = operation; ... ^{ AFHTTPRequestOperation * op = unretainedOperation; 在ARC
最简单的解决方案如下所示:
即使您打破了引用循环,< /em> Block 没有理由首先保留
AFHTTPRequestOperation
(假设操作在完成处理程序完成之前保持活动状态,但这并不总是保证 但一般来说如果使用self
进一步调用堆栈,则为 true 并由 ARC 假定)。最好的解决办法似乎是更新到 最新的 AFNetworking,它将操作作为参数传递到块中。
This appears to be the problem described by Conrad Stoll in Blocks, Operations, and Retain Cycles, but his writeup misses a few important points:
__block
looks like the Apple-recommended way of avoiding a strong reference to captured variables in MRC mode but is completely unnecessary in ARC mode. In this case, it is completely unnecessary in ARC mode; it is also unnecessary in MRC mode though the lighter-weight workaround is much more verbose:void * unretainedOperation = operation; ... ^{ AFHTTPRequestOperation * op = unretainedOperation; }
The simplest solution looks like this:
Even if you break the reference cycle, there is no reason for the Block to retain the
AFHTTPRequestOperation
in the first place (assuming the operation keeps itself alive until the completion handler completes, which isn't always guaranteed but is generally true and assumed by ARC if it is referred to usingself
further up the call stack).The best fix appears to be to update to the latest AFNetworking, which passes the operation into the block as an argument.