Hi Pushkar,

> On Sep 13, 2016, at 12:20 PM, Pushkar N Kulkarni <pushkar...@in.ibm.com> 
> wrote:
> 
> Hi Tony, Philippe, other onlookers, 
> 
> Long note. Kindly bear with me. 
> 
> I've created SR-2631 <https://bugs.swift.org/browse/SR-2631> to report a 
> crash in a very basic usage of URLSession. I'm providing a general synopsis 
> of the problem below and proposing two approaches to solve it.
> 
> The test case attached to the report creates a URLSession object locally 
> inside a function run(), which also creates a dataTask with a completion 
> handler, resumes the task and exits. On exiting run(), the URLSession object 
> has no references pointing to it. It is cleaned up and we crash while trying 
> to resume the task (the resume code and the subsequent callbacks are all 
> asynchronous). 
> 
> This brings us to a basic flaw in the current NSURLSession implementation. 
> Sessions and tasks are either created with delegates or callbacks, which are 
> invoked asynchronously. Both delegates and callbacks need the URLSession 
> objects they were registered with. Delegates need them until the last 
> delegate method invocation returns. Completion handlers need them just until 
> before they are invoked. The current implementation does not attempt to keep 
> the URLSession object alive for the subsequent asynchronous code invocations. 
> Hence the crash. 
> 
> Two questions arise when we think of a solution:
> 1. How can we keep the live URLSession objects alive?
> 2. What trigger can we use to clean them up?
> 
> I try to answer (2) first. The URLSession programming guide 
> <https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/URLLoadingSystem/NSURLSessionConcepts/NSURLSessionConcepts.html>
>  says:
> 
> "When you no longer need a session, invalidate it by calling either 
> invalidateAndCancel (to cancel outstanding tasks) or 
> finishTasksAndInvalidate(to allow outstanding tasks to finish before 
> invalidating the object). *** The session object keeps a strong reference to 
> the delegate until your app explicitly invalidates the session. If you do not 
> invalidate the session, your app leaks memory.*** "
> 

Interesting, this is counter to the usual pattern of delegation but I can see 
why it’s required here. Usually we want our delegates to be zeroing weak 
references.

> The URLSession references also mention that "invalidateAndCancel" and 
> "finishTasksAndInvalidate" break references to the callback and delegate 
> objects and make the session object unusable. *** So, it is apparent that 
> these methods are used to trigger a clean up of the session object ***
> 
> 
> Now coming to possible answers to (1). I can think of two ways of retaining 
> the session object:
> 
> 1. We intentionally maintain a retain cycle between the session and task 
> objects (URLSession <---> URLSessionTask)
> Currently the task object keeps an unowned reference to the session object. 
> We could make it a strong reference.  And break it when invalidateAndCancel 
> or finishTasksAndInvalidate are called. Alternatively, in the case of a 
> completion handler, we could break the cycle just before invoking the 
> handler. As long as we break the cycle eventually, I'm not sure if it could 
> have side effects. 
> 

This is probably the most reasonable approach.

Thanks for looking into this!

- Tony

> 2. We maintain all live sessions in a static array or dictionary in the 
> URLSession class. We remove them on session invalidation or callback 
> invocation. Doing this bookkeeping and searching may involve a cost and 
> scalability may be a problem here.
> 
> 
> Do you have any other approaches to consider? Can you please let me know your 
> opinion on the ones detailed above ? 
> 
> Thank you! 
> 
> Pushkar N Kulkarni,
> IBM Runtimes
> 
> Simplicity is prerequisite for reliability - Edsger W. Dijkstra
> 
> 

_______________________________________________
swift-corelibs-dev mailing list
swift-corelibs-dev@swift.org
https://lists.swift.org/mailman/listinfo/swift-corelibs-dev

Reply via email to