Reputation: 1745
I'm unable to find error in this code:
-(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];
}
In this form I've got a memory leak from instruments. I was assuming it is because I've lacked the __block keyword before: ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
But when I've added this keyword to above line I've got error like:
* -[NSConcreteMutableData isNSData__]: message sent to deallocated instance 0xdeab380
I do not know how to retain the request data and not leak memory.
Upvotes: 0
Views: 1506
Reputation: 28349
I know nothing about this library, so you should probably heed the advice of viking inthat regard.
However, I can help you with your leak, which is a result of the retain cycle created between the block and the request object. Specifically, note that your request
object is holding a strong reference to the code block object (via request.completionBlock
).
In turn, your code block object is holding a strong reference to request
because it accesses request.responseData
. Further, note that your code looks like it is most likely ARC, but that does not explain your _self
variable construct, which looks like a non-ARC weak reference. Non-ARC __block did not retain the object. Under ARC, __block does cause a retain.
Assuming ARC, I would suggest the following change.
-(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];
}
Now, the completion block holds a weak reference to the response object, which breaks the retain cycle. Note, in general, you should create a local strong reference to a weak reference, to make sure the object stays around long enough to do its job. However, in this specific case, it does not appear to be necessary. I assume it's OK to have a nil image.
Upvotes: 3
Reputation: 52227
- (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];
}
seems like the request itself needs to be marked with __block
Note, that the original author of ASIHTTPRequest isnt supporting it anymore. He explains his reasons very well and give links and suggestions for alternative projects. I am happy with AFNetworking, that has a great block based interface.
Upvotes: 1