Skip to content
This repository has been archived by the owner on Feb 2, 2023. It is now read-only.

NSURLSession is holding a strong reference to its delegate (retain cycle) #763

Closed
TernTuring opened this issue Oct 22, 2015 · 6 comments
Closed

Comments

@TernTuring
Copy link

Launch app, the memory is low.When I push a new view, but the memory lasting increased when scrolling the table , and don't release the memory after pop the view.

Thanks.

The code: https://github.com/TernTuring/ASDKTest.git

@appleguy
Copy link
Contributor

@TernTuring thanks for the test project! I've isolated the issue.

In your test, going back from the view does release most memory — such as ASDataController, which includes all ASDisplayNodes, etc. However, the ASBasicImageDownloaders do stay alive.

The problem is that NSURLSession has non-standard memory semantics for its delegate property. It's a strong reference, which actually is the only example of a strong delegate that I can think of in the Cocoa APIs... https://developer.apple.com/library/ios/documentation/Foundation/Reference/NSURLSession_class/index.html

"The session object keeps a strong reference to the delegate until your app exits or explicitly invalidates the session. If you do not invalidate the session, your app leaks memory until it exits."

Now the question is how to resolve this correctly.

@appleguy appleguy changed the title Memory cost too high when scrolling the table, and don't release the memory after pop up the view. NSURLSession is holding a strong reference to its delegate (retain cycle) Oct 24, 2015
@appleguy
Copy link
Contributor

@victormayorov I'm looking at this code and realized there are a few decisions in its architecture that I'm not fully familiar with and wondering if you can weigh in.

We create our own NSURLSession, instead of using +sharedSession. Is this necessary? It would seem to be more efficient to use the same object, especially because the session probably does some degree of concurrency limiting to more efficiently manage the network bandwidth.

More importantly, it would then also make sense to avoid using the delegate property entirely, and have a completion block. The block would of course retain self during the task pending, but if it gets cancelled (which occurs when the ASNetworkImageNode is deallocating) or finishes naturally, then the block would run and be destroyed — freeing the ASBasicImageDownloader and breaking the cycle.

If you have any time to look at the code and consider making those changes, I'd be greatly appreciative. It would allow me to focus on a few other changes I'd like to do. Just let me know if you're not available though, and I will start reading more deeply about NSURLSession (since it came out with iOS 7 & I used custom networkers in most of my projects, it's quite new to me).

@appleguy
Copy link
Contributor

@garrettmoon and I are going to investigate integrating PINRemoteImage with ASDK as a solution for this. If we do so, ASBasicImageDownloader would be powered by PINRemoteImage (or perhaps replaced / removed entirely).

If anyone else has time to investigate a more targeted fix here, which requires some refactoring of ASBasicImageDownloader, it would be appreciated. @TernTuring I'm pretty confident you could figure out a solution, too; basically we need to use something like a completionBlock instead of a persistent delegate so that the retain cycle is only temporary, and does end when the request finishes or is cancelled.

@TernTuring
Copy link
Author

@appleguy, thank you helping me! But I didn't find prefect solution now.

@appleguy
Copy link
Contributor

@TernTuring Thanks for giving it a shot. I will try to implement a solution on Wednesday, but I won't have the full day to code (normally I have more) and also need to release ASDK 1.9.

Try implementing an image downloader yourself with PINRemoteImage or SDWebImage. Both are projects you can easily install with a pod. You can make any object in your app the downloader for your ASNetworkImageView (it has an initializer where you pass in a downloader). The protocol to download images is very simple to forward to either of those frameworks.

Let me know how it goes if you can try. It shouldn't take more than an hour or so, I'd think (could be missing something, tell me if so)

@appleguy
Copy link
Contributor

appleguy commented Nov 8, 2015

Yay, I was able to fix this a couple weekends ago. Thanks @TernTuring and for confirming you never see this again.

@appleguy appleguy closed this as completed Nov 8, 2015
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants