0

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

-(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

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

4

2 回答 2

3

我对这个图书馆一无所知,所以在这方面你应该听从 viking 的建议。

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

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

假设 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];
}

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

于 2012-08-22T19:36:15.670 回答
1

来自文档

- (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


请注意,ASIHTTPRequest 的原作者不再支持它。他很好地解释了他的理由,并为替代项目提供了链接和建议。我对AFNetworking很满意,它有一个很棒的基于块的界面。

于 2012-08-22T18:41:15.703 回答