NSURLSession Memory Leaks occur when using web services in IOS
After rereading the URL Loading System Programming Guide it turns that I was setting the NSURLSession
property to nil too early.
Instead, I need to set the NSURLSession
property to nil AFTER I receive the delegate message URLSession:(NSURLSession *)session didBecomeInvalidWithError:(NSError *)error
, which makes sense. Luckily, it was a minor mistake.
E.g.
- (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(NSError *)error
{
if (error)
{
#ifdef DEBUG
NSLog(@"[GPPhotoRequest] Session Invalidation: %@", [error description]);
#endif
}
if ([session isEqual:_session])
{
[self cleanupSession];
}
}
NSURLSession HTTP/2 memory leak
From apple doc:
The session object keeps a strong reference to the delegate until your app exits or explicitly invalidates the session. If you don’t invalidate the session, your app leaks memory until it exits.
Also looking at your project https://github.com/upyun/swift-sdk/tree/testleak you need to call finishTasksAndInvalidate() after sessionTask.resume() since you are creating session per request
Swift 3 URLSession memory leak
Shared URL session has a credential storage for cookies and other "browser" stuff. Since it's shared it is a singleton which will live forever in your application. Instruments interprets this as a leak.
Advice: repeat the action several times before you look for leaks.
Also, quite likely the self reference in your callback holds onto your view controller while your request is still pending. Use weak self at the block start to break the cycle. But that totally depends on your design. It got me at least in a few cases.
I also want to refer to this answer: https://stackoverflow.com/a/35757989/3351794
NSURLSession: method dataTaskWithRequest never reach completion callback on lengthy responses
When fetching large resources, you should use download task. A data task will attempt to load the entire response in a single NSData
object. Loading a large asset in memory at the same time is not only inefficient, but if it is extraordinarily large, can cause problems.
A download task is well suited for these tasks, because it will stream the asset to a temporary file for you, reducing the peak memory usage. (Admittedly, you can manually achieve the same with data task with delegate pattern, but download tasks do this for you.)
You said:
I saw that there's an alternative method in
NSURLSession
dedicated for downloading files calleddownloadTaskWithRequest
but it doesn't have an async completion block.
Two observations:
There is a rendition,
dataTaskWithRequest:completionHandler:
, that has a completion block:NSURLSession* session = [NSURLSession sharedSession];
NSURLSessionDownloadTask *task = [session downloadTaskWithRequest:request completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
...
}];
[task resume];Note, I would advise using
sharedSession
if you are not setting a delegate, or otherwise customizing yourNSURLSession
. You do not want to instantiateNSURLSession
objects unnecessarily. And if you really must instantiate aNSURLSession
, re-use it for subsequent tasks and/or make sure to callfinishTasksAndInvalidate
after submitting the last task for that session, or else theNSURLSession
will leak. And, if you instantiate your ownNSURLSession
, you do not have to instantiate your own operation queue, as it will, by default, create a serial queue for you if you do not supply an operation queue.The rendition without a block parameter,
downloadTaskWithURL:
, works, too. All you need to do is to specify adelegate
for yourNSURLSession
and then and implementURLSession:downloadTask:didFinishDownloadingToURL:
.The reason I suggest this is that, often, when we are downloading very large assets (especially over cellular), we realize that the users may want to leave our app and let the download complete in the background. In those situations, we would use a background
NSURLSessionConfiguration
. And when using background sessions, you must use this delegate-based approach. So, if you think you might eventually adopt background sessions for long downloads, then adopting a delegate-based approach now is not a bad idea.For more information, see Downloading Files in the Background.
Related Topics
How to Obtain Certificate Signing Request
Switching Between Text Fields on Pressing Return Key in Swift
How to Add Particle Effects to an iOS App That Is Not a Game Using iOS 7 Spritekit Particle
How to Crop Image Inside the Circle in Uiimageview in iOS
Xcode: Issue "File Xxx.Png Is Missing from Working Copy" at Project Building
How to Prevent Screen Lock on My Application with Swift on iOS
Programmatically Fire Button Click Event
Change Tab Bar Tint Color on iOS 7
Inputaccessoryview Docked at Bottom
iOS Change Navigation Bar Title Font and Color
How to Restrict Uitextfield to Take Only Numbers in Swift
Record, Save And/Or Convert Video in Mp4 Format
No Suitable Records Were Found Verify Your Bundle Identifier Is Correct
How to Fade a Uivisualeffectview And/Or Uiblureffect in and Out