ARC异步阻止最佳实践

时间:2015-07-16 21:14:42

标签: ios http automatic-ref-counting nsurlrequest

我的应用程序通过HTTP请求发送大量消息。我在HTTP请求周围编写了一个简单的包装器,它有一个主要方法来触发请求并返回任何NSData作为结果。

看起来像这样:

- (void)sendRequest:(NSURLRequest *)request {
    [[[NSURLSession sharedSession] dataTaskWithRequest:request
                                     completionHandler:^(NSData *data,
                                                         NSURLResponse *response,
                                                         NSError *error) {
                                         NSLog(@"---->> request returned");

                                         if (_delegate == nil)
                                             return;

                                         if (error == nil) {
                                             // forward along
                                             [_delegate requestReturnedResult:data withResponse:response];

                                         }
                                         else {
                                             // error occurred
                                             [_delegate requestReturnedError:error withResponse:response];
                                         }
                                     }] resume];
}

这个HttpRequestHelper对象是我的消息抽象对象ivar的{​​{1}},它打包数据然后将其发送出去。

我认为有一个OutboundMessage对象可以获取一些数据,创建一个MessageSender对象并将其发送出去。

这种抽象很有效,除了我认为我遇到了ARC的问题。

当有人致电OutboundMessage时,我[MessageSender send:] alloc并发送出去。

我通过OutboundMessage看到的是我的NSLog已清除(大概是OutboundMessage退出时,我看到send已清理。然后< / strong>我在HttpRequestHelper的完成处理程序中看到NSLog

这向我表明,在HTTP请求完成之前,我的请求帮助程序周围的所有内容都已清除。然后你可以想象,我很快就会通过dataTaskWithRequest冒出我的回复,我得delegate

我可以想出一些创造性的方法来防止重新分配并防止这种情况,但我想知道的是概念上处理这种触发消息模式的最佳做法是什么,只有在请求发生后才能清除包络对象完成。

感谢。

更新 每个包装器对象都使用exc_bad_access样式模式,我注意到这些代理被保存为:

initWithDelegate:self

我将它们更改为@property (nonatomic, assign) id<HttpRequesterDelegate> delegate; 并且它似乎纠正了它,但我不确定我现在是否在泄漏记忆,或者是否有更优化的方法。

1 个答案:

答案 0 :(得分:1)

首先,由NSURLSessionDataTask方法创建的NSURLSession - dataTaskWithRequest:completionHandler:对象保留completionHandler块对象。在数据任务完成时执行块之前,块对象不会被释放。

接下来,Blocks自动捕获(保留)局部变量。代码中的以下行

if (_delegate == nil)

相同
if (self.delegate == nil)

如果delegate属性为strong

@property (nonatomic, strong) id<HttpRequesterDelegate> delegate;

然后self被块保留。在这种情况下,selfHttpRequestHelper个对象。因此,只要数据任务完成,HttpRequestHelper对象和delegate对象就会生效。这很安全。

delegate属性为assign

@property (nonatomic, assign) id<HttpRequesterDelegate> delegate;

__unsafe_unretained相同。块根本不会保留__unsafe_unretained个对象。因此self未被保留,它将在数据任务完成之前被释放。

<强> ADDED

在这种情况下,您可以使用局部变量来保留delegate个对象。因为completionHandler仅使用delegate对象,而不使用HttpRequestHelper对象本身。

id<HttpRequesterDelegate> delegate = _delegate;

[[[NSURLSession sharedSession] dataTaskWithRequest:request
                                 completionHandler:^(NSData *data,
                                                     NSURLResponse *response,
                                                     NSError *error) {
                                     NSLog(@"---->> request returned");

                                     /*
                                      * Use `delegate` instead of `_delegate`
                                      */
                                     if (delegate == nil)
                                         return;

                                     ...

在这种情况下,delegate属性的属性很强或分配,它根本不重要。