<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">Hi Pushkar,<div class=""><br class=""><div><blockquote type="cite" class=""><div class="">On Sep 13, 2016, at 12:20 PM, Pushkar N Kulkarni <<a href="mailto:pushkar.nk@in.ibm.com" class="">pushkar.nk@in.ibm.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><font face="Verdana,Arial,Helvetica,sans-serif" size="2" class=""><div class="">Hi Tony, Philippe, other onlookers, </div><div class=""><br class=""></div><div class="">Long note. Kindly bear with me. </div><div class=""><br class=""></div><div class="">I've created <a target="_blank" href="https://bugs.swift.org/browse/SR-2631" title="https://bugs.swift.org/browse/SR-2631" class="">SR-2631</a> 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.</div><div class=""><br class=""></div><div class="">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). </div><div class=""><br class=""></div><div class="">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. </div><div class=""><br class=""></div><div class="">Two questions arise when we think of a solution:</div><div class="">1. How can we keep the live URLSession objects alive?</div><div class="">2. What trigger can we use to clean them up?</div><div class=""><br class=""></div><div class="">I try to answer (2) first. The <a target="_blank" href="https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/URLLoadingSystem/NSURLSessionConcepts/NSURLSessionConcepts.html" title="https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/URLLoadingSystem/NSURLSessionConcepts/NSURLSessionConcepts.html" class="">URLSession programming guide</a> says:</div><div class=""><br class=""></div><div class=""><div style="margin-top: 0.667em; margin-bottom: 0.833em; font-size: 13px; line-height: normal; font-family: 'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif; display: inline;" class="">"When you no longer need a session, invalidate it by calling either <code style="font-family: Courier, Consolas, monospace;" class=""><font color="#666666" class="">invalidateAndCancel</font></code> (to cancel outstanding tasks) or <code style="font-family: Courier, Consolas, monospace;" class=""><font color="#666666" class="">finishTasksAndInvalidate</font></code>(to allow outstanding tasks to finish before invalidating the object). *** </div><span style="font-family: 'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif; font-size: 13px; background-color: rgb(240, 243, 247);" class="">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.*** "</span></div><div class=""><br class=""></div></font></div></blockquote><div><br class=""></div>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.</div><div><br class=""><blockquote type="cite" class=""><div class=""><font face="Verdana,Arial,Helvetica,sans-serif" size="2" class=""><div class="">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 ***</div><div class=""><br class=""></div><div class=""><br class=""></div><div class="">Now coming to possible answers to (1). I can think of two ways of retaining the session object:</div><div class=""><br class=""></div><div class="">1. We intentionally maintain a retain cycle between the session and task objects (URLSession <---> URLSessionTask)</div><div class="">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. </div><div class=""><br class=""></div></font></div></blockquote><div><br class=""></div><div>This is probably the most reasonable approach.</div><div><br class=""></div><div>Thanks for looking into this!</div><div><br class=""></div><div>- Tony</div><br class=""><blockquote type="cite" class=""><div class=""><font face="Verdana,Arial,Helvetica,sans-serif" size="2" class=""><div class="">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.</div><div class=""><br class=""></div><div class=""><br class=""></div><div class="">Do you have any other approaches to consider? Can you please let me know your opinion on the ones detailed above ? </div><div class=""><br class=""></div><div class="">Thank you! <br class=""></div><div class=""><font face="Verdana,Arial,Helvetica,sans-serif" size="2" class=""><font class=""><font class=""><div class="socmaildefaultfont" dir="ltr"><div class="socmaildefaultfont" dir="ltr"><div class="socmaildefaultfont" dir="ltr"><div dir="ltr" style="font-style: normal;" class=""><br class=""><font face="Sans Serif, Verdana, Arial, Helvetica, sans-serif" class="">Pushkar N Kulkarni,</font></div>
<div dir="ltr" style="font-style: normal;" class=""><font face="Sans Serif, Verdana, Arial, Helvetica, sans-serif" class="">IBM Runtimes</font></div><div dir="ltr" style="font-style: normal;" class=""><font face="Sans Serif, Verdana, Arial, Helvetica, sans-serif" class=""><br class=""></font></div><div dir="ltr" class=""><font face="serif, Times New Roman, Times, serif" class=""><i class="">Simplicity is prerequisite for reliability - Edsger W. Dijkstra</i></font></div>
<div dir="ltr" style="font-style: normal; font-size: 10.5pt; font-family: Arial;" class=""><br class=""></div></div></div></div></font></font></font></div></font><br class="">
</div></blockquote></div><br class=""></div></body></html>