ASIHTTPRequest阻止内存泄漏

时间:2012-08-22 18:30:39

标签: objective-c ios cocoa-touch asihttprequest objective-c-blocks

我无法在此代码中找到错误:

-(void)downloadImageFromURL:(NSURL*)url withCompletionBlock:(RSSMessageImageDownloadCompletionBlock)completionBlock
{

    ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];

    __block RSSMessage *_self = self;
    request.completionBlock =
    ^{    
        __block NSData *responseData = request.responseData;

        dispatch_async( dispatch_get_main_queue(), ^{
            _self.image = responseData;            
            [[[UIApplication sharedApplication] delegate] saveContext];
            if(completionBlock != nil)
            {
                completionBlock();
            }

        });
    };

    [request startAsynchronous];
}

在这种形式下,我的乐器有内存泄漏。我之所以认为是因为我之前缺少__block关键字:ASIHTTPRequest * request = [ASIHTTPRequest requestWithURL:url];

但是当我将这个关键字添加到上面的行时,我会收到如下错误:

  

* - [NSConcreteMutableData isNSData__]:发送到解除分配的实例0xdeab380的消息

我不知道如何保留请求数据而不是泄漏内存。

2 个答案:

答案 0 :(得分:3)

我对这个图书馆一无所知,所以你应该注意维京人的建议。

但是,我可以帮助您解决泄漏问题,这是在块和请求对象之间创建的保留周期的结果。具体来说,请注意您的request对象持有对代码块对象的强引用(通过request.completionBlock)。

反过来,您的代码块对象保留了对request的强引用,因为它访问request.responseData。此外,请注意您的代码看起来很可能是ARC,但这并不能解释您的_self变量构造,它看起来像非ARC弱引用。非ARC __block未保留该对象。在ARC下,__ lock确实会导致保留。

假设ARC,我建议进行以下更改。

-(void)downloadImageFromURL:(NSURL*)url withCompletionBlock (RSSMessageImageDownloadCompletionBlock)completionBlock
{
    ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];

    __weak ASIHTTPRequest *weakRequest = request;
    __weak RSSMessage *weakSelf = self;

    request.completionBlock = ^{
        NSData *responseData = weakRequest.responseData;
        // Check for nil if not ok with nil data
        dispatch_async( dispatch_get_main_queue(), ^{
            weakSelf.image = responseData;            
            [[[UIApplication sharedApplication] delegate] saveContext];
            if(completionBlock != nil)
            {
                completionBlock();
            }
        });
    };
    [request startAsynchronous];
}

现在,完成块包含对响应对象的弱引用,这会破坏保留周期。请注意,通常,您应该创建对弱引用的本地强引用,以确保对象保持足够长的时间来完成其工作。但是,在这种特定情况下,似乎没有必要。我认为没有图像可以。

答案 1 :(得分:1)

from the docs

- (IBAction)grabURLInBackground:(id)sender
{
   NSURL *url = [NSURL URLWithString:@"http://allseeing-i.com"];
   __block ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
   [request setCompletionBlock:^{
      // Use when fetching text data
      NSString *responseString = [request responseString];

      // Use when fetching binary data
      NSData *responseData = [request responseData];
   }];
   [request setFailedBlock:^{
      NSError *error = [request error];
   }];
   [request startAsynchronous];
}

似乎请求本身需要标有__block


注意,original author of ASIHTTPRequest isnt supporting it anymore。他很好地解释了他的理由,并为替代项目提供了链接和建议。我对AFNetworking很满意,它有一个很好的基于块的界面。