【问题标题】:ASIHTTPRequest / ASIFormDataRequest - referencing request object within blocks under ARCASIHTTPRequest / ASIFormDataRequest - 在 ARC 下的块中引用请求对象
【发布时间】:2012-02-10 04:36:58
【问题描述】:

this question 非常相似,我正在尝试将使用ASIHTTPRequestASIFormDataRequest 的项目转换为ARC。

在我的视图控制器类中,我经常在完成块中引用和使用request 对象的属性(查看响应代码、响应数据等):

__block  ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:[NSURL URLWithString:SOME_URL]];    
[request setCompletionBlock:^{   

    if([request responseStatusCode] == 200) ....etc

转换为 ARC 时,我收到警告:

在此块中强烈捕获“请求”可能会导致 保留周期

这样做的正确方法是什么?

另一个 SO 用户在上一个线程中指出,简单地添加 __weak 可能会导致请求在块完成之前被释放,我相信这是真的。

如何在 ARC 下的完成/失败块中正确引用这些属性?

【问题讨论】:

    标签: iphone objective-c ios asihttprequest automatic-ref-counting


    【解决方案1】:

    (我阅读了您对另一个问题的评论)

    在使用ASIHTTPRequest 实现了更多模块后,我了解到最好的方法是保留对您的请求对象的strong 引用。在你的情况下,你可以这样做:

    self.request = [ASIFormDataRequest requestWithURL:[NSURL URLWithString:SOME_URL]];
    __weak ASIFormDataRequest *weakRequest = self.request; // __block directive not needed since we only access the instance's properties. 
    [self.request setCompletionBlock:^{   
    
        if([weakRequest responseStatusCode] == 200)
        // ...
    

    这样,即使在您开始请求(例如取消)后,您仍然可以控制self.request。当您准备好释放您的请求时,您可以执行self.request = nil;,可能在您的完成块或self.request 的父对象的清理方法中。

    更新:

    如果您的目标是 iOS 5 之前的版本,那么共同点是:使用 __unsafe_unretained 而不是 __weak。这没关系,因为查看ASIHTTPRequest.m,块在其dealloc() 中被nil 删除(即它们不应该被执行)。虽然我还没有测试过,所以请确保仍然在启用 NSZombies 的情况下进行测试。

    注意:

    取消ASIHTTPRequest 对象的唯一安全方法是调用其clearDelegatesAndCancel 方法。当我刚使用普通的cancel 时,我被一些讨厌的虫子咬了。

    【讨论】:

    • 如果您的目标是 iOS 5 之前的版本怎么办?
    • 如果您正在创建一组要添加到 NSOperationQueue 的请求怎么办?
    • 虽然我还没有尝试过,但是NSOperationQueue's ``addOperation` 上的文档说队列保留/保持对操作的强引用。实际上,它应该与保留 self.request 属性相同。
    • 这也解决了我的问题。另一个答案的 cmets 中的 Juan 描述了我遇到的确切问题,它在调试中运行良好,但随后在 adhoc 上崩溃并在发布版本中崩溃。幸运的是,我在一天之内就发现了这个问题,而不是整个审批周期。
    【解决方案2】:

    如果您的目标是 5.0 之前的 iOS 版本,则不包括 weak 支持:

    __unsafe_unretained __block ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
    

    【讨论】:

    • 另见:stackoverflow.com/questions/7205128/…(可能重复)
    • 这种方法效果不好,至少在 iOS 5.0+ 上是这样。出于某种原因,如果从 xcode 启动应用程序将在模拟器和设备上启动,但是如果它是使用临时分发(例如 TestFlight)安装的,它会在启动应用程序时立即崩溃。改用接受的答案建议的方法!
    • barfoon,问题显示为已链接因为我已链接到它。
    • 岩浆..胡安是绝对正确的。此方法不适用于 ios5+。它对我做同样的事情,我来到这里试图找到答案。我的临时版本突然崩溃,而调试版本没有。这并不容易,但我追踪到了这行代码。在这种情况下,“请求”立即被释放,然后在尝试对其执行任何操作时导致访问错误。但仅在发布版本中,不在调试版本中。
    • @badweasel 当使用缺乏 __weak 支持的 iOS 版本时,这可以完美地回答操作员提出的问题,即“在 ARC 下的块中引用请求对象”。另一个答案使用 __weak 引用,旧 iOS 版本不支持。这是做到这一点的方法。当然,你必须意识到你不能依赖花哨的 __weak 机制,如果你不知道如何正确处理指针,你会崩溃。很抱歉,这是您没有正确管理指针的错,而不是我的答案的错。投反对票是不恰当的。
    【解决方案3】:

    我发现这个答案很有帮助:https://stackoverflow.com/a/7735770/133875

    它说要使用__unsafe_unretained 以及__block

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-07-03
      • 1970-01-01
      • 2012-03-09
      • 2012-01-31
      • 2012-03-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多