【问题标题】:Objective C ASIHTTPRequest nested GCD block in complete blockObjective C ASIHTTPRequest 在完整块中嵌套 GCD 块
【发布时间】:2012-09-19 20:12:52
【问题描述】:

我想知道这是否是让嵌套块在 Objective C 中处理同一变量而不会导致任何内存问题或 ARC 崩溃的正确方法。它以 ASIHttpRequest 完成块开始。

MyObject *object = [dataSet objectAtIndex:i];

ASIHTTPRequest *request = [[ASIHTTPRequest alloc]initWithURL:@"FOO"];

__block MyObject *mutableObject = object;

[request setCompleteBlock:^{

      mutableObject.data = request.responseData;

      __block MyObject *gcdMutableObject = mutableObject;

      dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^{

              [gcdMutableObject doLongComputation];

              dispatch_async(dispatch_get_main_queue(),^{

                     [self updateGUIWithObject:gcdMutableObject];
              }); 

      });

[request startAsynchronous];

我主要关心的是嵌套调度队列并使用前一个队列的 __block 版本来访问数据。我所做的安全吗?

【问题讨论】:

  • 为什么你有这么多指向同一个对象的指针?此外,这不是“安全”问题,而是您想要发生的事情。如果您指定所需的意图,这将有助于提供更合适的响应。否则,我很想看看那段代码,摇摇头,然后继续前进。
  • 我的意图是在每个块级别修改对象并在最里面的块中安全地返回到主线程。
  • 你在滥用 __block。只需使用一次。

标签: objective-c automatic-ref-counting asihttprequest objective-c-blocks grand-central-dispatch


【解决方案1】:
// Under ARC the blocks will automatically retain <object>
MyObject *object = [dataSet objectAtIndex:i];
ASIHTTPRequest *request = [[ASIHTTPRequest alloc]initWithURL:@"FOO"];
__weak ASIHTTPRequest *weakRequest = request;                        // EDIT
[request setCompleteBlock:^{
    // <object> is retained by the block.
    // Changing a property of <object> but not <object> itself.
    ASIHTTPRequest *request = weakRequest;                           // EDIT
    if (!request) return;                                            // EDIT
    object.data = request.responseData;    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^{
        // <object> retained by this block too...
        [object doLongComputation];
        dispatch_async(dispatch_get_main_queue(),^{
            // <object> retained by this block too
            // Note, <self> is also retained...
            // Use the same "weak" trick if you don't want this      // EDIT
            [self updateGUIWithObject:object];
        });
    });
}];
[request startAsynchronous];

编辑

endy 确实提出了一个有效的观点(尽管通常应该避免使用__usnafe_unretained。虽然我最初确实注意到请求和自我都保留在原始帖子中,但我认为必要时会采取适当的措施。这对我来说并不是一个错误的决定。

因此,有几种方法可以打破此请求的保留周期,但在这里使用弱引用可能是最安全和最好的选择。

见上面代码中标有// EDIT的行。

【讨论】:

  • 谢谢,这正是我想要的。不确定修改属性是否需要 __block 标记
  • 这将导致一个保留周期。 imagesnatcher.com/img/8c8cf03df804b7f3/f5a836.png
  • 如代码注释中所述......作为对正在发生的事情的解释。有很多方法可以处理保留周期,其中最糟糕的是使用 __unsafe_unretained
  • @endy - 你是对的。尽管我在 cmets 中特别指出了保留,但我应该指出如何避免它。谢谢。
  • 现在您只需编写 3 倍的代码,以避免请求在分配后被释放。我向你保证, __unsafe_unretained 与静态 requestWithURL 一起工作得很好。如果使用得当,使用 __unsafe_unretained 没有任何问题。
【解决方案2】:

我对指向同一个对象的所有指针有点迷茫,但我认为这就是你要找的。

__block MyObject *object = [dataSet objectAtIndex:i];

__unsafe_unretained ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"FOO"]];


[request setCompleteBlock:^{

      object.data = request.responseData;


      dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^{

              [object doLongComputation];

              dispatch_async(dispatch_get_main_queue(),^{

                     [self updateGUIWithObject:object];
              }); 

      });
}];
[request startAsynchronous];

【讨论】:

  • __unsafe_unretained ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"FOO"]]; 这里有危险。
  • 没有。这里没有保留周期。不要被名称中的不安全因素分心。
  • 如果你想避免保留循环,最后的手段是__unsafe_unretained。使用__weak 在几乎所有情况下都更合适,包括这种情况。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-07-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多