Nayeemuddin Shaik
Nayeemuddin Shaik

Reputation: 53

memory leak for NSURLSession

In xcode instruments i am getting this method memory leak

- (void)getDataForRequest:(NSURLRequest *)request completionHandler:(downloadCompletionBlock)completionHandler
{
    self.expectedLength = 0;
    self.currentLength = 0;
    self.responseData = Nil;
    
    self.contentLengthBlock = nil;
    self.completionBlock = completionHandler;
    
    NSURLSession *session = [NSURLSession sharedSession];
    
    NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
    
    session = [NSURLSession sessionWithConfiguration:defaultConfigObject delegate: self delegateQueue: [NSOperationQueue mainQueue]];
    
    self.postDataTask = [session dataTaskWithRequest:request];
    
    [self.postDataTask resume];
}

Upvotes: 1

Views: 798

Answers (2)

Rob
Rob

Reputation: 438297

A problem in this code snippet is that you are creating a new NSURLSession for every request and you never invalidate the sessions. If you call finishTasksAndInvalidate after the request is initiated, it will:

  • reclaim the memory associated with the NSURLSession when the request finishes; and by doing so, it will also
  • release the strong reference to the delegate object.

Thus:

- (void)getDataForRequest:(NSURLRequest *)request completionHandler:(DownloadCompletionBlock)completionHandler {
    self.expectedLength = 0;
    self.currentLength = 0;
    self.responseData = nil;

    self.contentLengthBlock = nil;
    self.completionBlock = completionHandler;

    NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
    NSURLSession *session = [NSURLSession sessionWithConfiguration:defaultConfigObject delegate:self delegateQueue:[NSOperationQueue mainQueue]];

    self.postDataTask = [session dataTaskWithRequest:request];

    [self.postDataTask resume];
    [session finishTasksAndInvalidate];
}

If you don't finishTasksAndInvalidate, you’ll see leaks like so:

enter image description here

Calling finishTasksAndInvalidate will resolve those issues.


There are two other (preferable) alternatives:

  • If you are using the delegate solely to process the body of the responses, then you might use the completion-handler block pattern of datataskwithurl:completionHandler: instead, then you might not need to use the delegate protocol at all. You could then use [NSURLSession sharedSession] and you don’t need to worry about invalidating the session at all;

  • If you really need the delegate (e.g., handling auth challenge requests, detecting redirects, etc.), you can still reconsider whether you need/want to create new session for each request. It’s generally preferable to instantiate a single NSURLSession, save a reference to it, and use that single NSURLSession (and its associated delegate) for multiple requests. It is more efficient and, again, saves you from needing to invalidate the session after every request.

Upvotes: 7

matt
matt

Reputation: 535989

The problem could be the phrase delegate: self. An NSURLSession retains its delegate. Thus you are telling the session to retain this instance (probably a view controller). The view controller cannot go out of existence until you invalidate the session.

The solution is: manage your session correctly. Keep a reference to the session so that you can invalidate it later. Even better, make the delegate a lightweight object, different from the view controller, whose memory you can manage.

Upvotes: 0

Related Questions