<html><head><meta http-equiv="Content-Type" content="text/html charset=us-ascii"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div><blockquote type="cite" class=""><div class="">On Aug 30, 2017, at 7:02 PM, Yvo van Beek &lt;<a href="mailto:yvo@yvo.net" class="">yvo@yvo.net</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" class="">Hi John,<div class=""><br class=""></div><div class="">I see that I've used <font face="monospace, monospace" class="">DispatchQueue.main</font> in my example which is probably a poor choice to demonstrate the issue:</div><div class=""><br class=""></div><div class=""><font face="monospace, monospace" color="#3d85c6" class="">&nbsp; class MyClass {</font></div><div class=""><font face="monospace, monospace" color="#3d85c6" class="">&nbsp; &nbsp; let queue =&nbsp;<span class="gmail-s1" style="font-size:13px">DispatchQueue</span><span class="gmail-s2" style="font-size:13px">(label: </span><span class="gmail-s3" style="font-size:13px">"MyApp.MyQueue"</span><span class="gmail-s2" style="font-size:13px">)</span></font></div><div class=""><span class="gmail-s2" style="font-size:13px"><font face="monospace, monospace" color="#3d85c6" class=""><br class=""></font></span></div><div class=""><span class="gmail-s2" style="font-size:13px"><font face="monospace, monospace" color="#3d85c6" class="">&nbsp; &nbsp; func start() {</font></span></div><div class=""><span class="gmail-s2"><font face="monospace, monospace" color="#3d85c6" class=""><div class="">&nbsp; &nbsp; &nbsp; queue.async {</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; otherClass.<span style="font-size:13px" class="">doSomethingThatTakesAWhile()</span></div></font><font face="monospace, monospace" color="#3d85c6" class=""><div class="">&nbsp; &nbsp; &nbsp; }</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; &nbsp; ...</div></font></span></div><div class=""><span class="gmail-s2" style="font-size:13px"><font face="monospace, monospace" color="#3d85c6" class=""><br class=""></font></span></div><div class=""><span class="gmail-s2" style="font-size:13px"><font face="monospace, monospace" color="#3d85c6" class="">&nbsp; &nbsp; &nbsp; queue.async {</font></span></div><div class=""><span style="color:rgb(61,133,198);font-family:monospace,monospace;font-size:13px" class="">&nbsp; &nbsp; &nbsp; &nbsp; self.doSomething()</span></div><div class=""><span class="gmail-s2" style="font-size:13px"><font face="monospace, monospace" color="#3d85c6" class="">&nbsp; &nbsp; &nbsp; }</font></span></div><div class=""><span class="gmail-s2" style="font-size:13px"><font face="monospace, monospace" color="#3d85c6" class="">&nbsp; &nbsp; }</font></span></div><div class=""><span class="gmail-s2" style="font-size:13px"><font face="monospace, monospace" color="#3d85c6" class="">&nbsp; }</font></span></div><div class=""><span class="gmail-s2" style="font-size:13px"><font face="monospace, monospace" color="#3d85c6" class=""><br class=""></font></span></div><div class=""><span class="gmail-s2">This would create a retain cycle wouldn't it?</span></div></div></div></blockquote><div><br class=""></div>You're correct that there's a temporary cycle which lasts until the queue executes the closure. &nbsp;However, temporary cycles like this rarely cause memory leaks for the same reason that local variables rarely cause memory leaks: eventually the closure will be executed or the function will return. &nbsp;The only way that a closure on a dispatch queue can cause a memory leak is if it constantly enqueues new closures that recreate the same cycle.</div><div><br class=""></div><div>If you're doing a dispatch with a very substantial delay (in the hundreds of milliseconds), it can still be a good idea to use a weak reference just so objects can be collected faster. &nbsp;But it's not strictly necessary just to avoid leaks.</div><div><br class=""></div><div>John.</div><div><br class=""><blockquote type="cite" class=""><div class=""><div dir="ltr" class=""><div class=""><span class="gmail-s2"><br class=""></span></div><div class=""><span class="gmail-s2">- Yvo</span></div><div class=""><span class="gmail-s2"><br class=""></span></div>







<div class=""><div class="gmail_extra"><br class=""><div class="gmail_quote">On Wed, Aug 30, 2017 at 6:48 PM, John McCall <span dir="ltr" class="">&lt;<a href="mailto:rjmccall@apple.com" target="_blank" class="">rjmccall@apple.com</a>&gt;</span> wrote:<br class=""><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word" class=""><br class=""><div class=""><span class="gmail-"><blockquote type="cite" class=""><div class="">On Aug 30, 2017, at 6:45 PM, Yvo van Beek via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a>&gt; wrote:</div><br class="gmail-m_-8240078540501221380Apple-interchange-newline"><div class=""><div dir="ltr" class=""><div class="">When I'm writing code I like it to be free from any distractions that aren't really relevant to the problem that I'm trying to solve. One of these distractions is having to pay a lot of attention to retain cycles. As my code grows, I start making extensions to simplify my code.</div><div class=""><br class=""></div><div class="">I've created the following helper for DispatchQueues:</div><div class=""><br class=""></div><div class="">&nbsp;<font face="monospace, monospace" class=""> <font color="#3d85c6" class="">extension DispatchQueue {</font></font></div><div class=""><font face="monospace, monospace" color="#3d85c6" class="">&nbsp; &nbsp; func async&lt;T: AnyObject&gt;(weak arg: T, execute: @escaping (T) -&gt; Void) {</font></div><div class=""><font face="monospace, monospace" color="#3d85c6" class="">&nbsp; &nbsp; &nbsp; async { [weak arg] in</font></div><div class=""><font face="monospace, monospace" color="#3d85c6" class="">&nbsp; &nbsp; &nbsp; &nbsp; if let argRef = arg { execute(argRef) }</font></div><div class=""><font face="monospace, monospace" color="#3d85c6" class="">&nbsp; &nbsp; &nbsp; }</font></div><div class=""><font face="monospace, monospace" color="#3d85c6" class="">&nbsp; &nbsp; }</font></div><div class=""><font face="monospace, monospace" color="#3d85c6" class="">&nbsp; }</font></div><div class=""><br class=""></div><div class="">It allows you to do this:</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp;<font face="monospace, monospace" color="#3d85c6" class="">DispatchQueue.main.async(<wbr class="">weak: self) { me in</font></div><div class=""><font face="monospace, monospace" color="#3d85c6" class="">&nbsp; &nbsp; me.updateSomePartOfUI()</font></div><div class=""><font face="monospace, monospace" color="#3d85c6" class="">&nbsp; }</font></div><div class=""><br class=""></div></div></div></blockquote><div class=""><br class=""></div></span><div class="">Closures handed off to dispatch queues will not cause retain cycles.</div><div class=""><br class=""></div><div class="">John.</div><br class=""><blockquote type="cite" class=""><div class=""><span class="gmail-"><div dir="ltr" class=""><div class="">When functions are passed as a closure, the compiler won't warn about a possible retain cycle (there is no need to prefix with self). That's why I've also created helpers for calling instance functions:</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp;&nbsp;<font face="monospace, monospace" color="#3d85c6" class="">func blockFor&lt;Target: AnyObject&gt;(_ target: Target, method: @escaping (Target) -&gt; () -&gt; Void) -&gt; () -&gt; Void {</font></div><div class=""><font face="monospace, monospace" color="#3d85c6" class="">&nbsp; &nbsp; return { [weak target] in</font></div><div class=""><font face="monospace, monospace" color="#3d85c6" class="">&nbsp; &nbsp; &nbsp; if let targetRef = target { method(targetRef)() }</font></div><div class=""><font face="monospace, monospace" color="#3d85c6" class="">&nbsp; &nbsp; }</font></div><div class=""><font face="monospace, monospace" color="#3d85c6" class="">&nbsp; }</font></div><div class=""><font face="monospace, monospace" color="#3d85c6" class=""><br class=""></font></div><div class=""><font face="monospace, monospace" color="#3d85c6" class="">&nbsp; func blockFor&lt;Target: AnyObject, Args&gt;(_ target: Target, method: @escaping (Target) -&gt; (Args) -&gt; Void, args: Args) -&gt; () -&gt; Void {</font></div><div class=""><font face="monospace, monospace" color="#3d85c6" class="">&nbsp; &nbsp; return { [weak target] in</font></div><div class=""><font face="monospace, monospace" color="#3d85c6" class="">&nbsp; &nbsp; &nbsp; if let targetRef = target { method(targetRef)(args) }</font></div><div class=""><font face="monospace, monospace" color="#3d85c6" class="">&nbsp; &nbsp; }</font></div><div class=""><font face="monospace, monospace" color="#3d85c6" class="">&nbsp; }</font></div><div class=""><br class=""></div><div class="">Calls look like this:</div><div class=""><br class=""></div><div class="">&nbsp;<font face="monospace, monospace" color="#3d85c6" class="">&nbsp;class MyClass {</font></div><div class=""><font face="monospace, monospace" color="#3d85c6" class="">&nbsp; &nbsp; func start() {</font></div><div class=""><font face="monospace, monospace" color="#3d85c6" class="">&nbsp; &nbsp; &nbsp; performAction(completion: blockFor(self, method: MyClass.done))</font></div><div class=""><font face="monospace, monospace" color="#3d85c6" class="">&nbsp; &nbsp; }</font></div><div class=""><font face="monospace, monospace" color="#3d85c6" class=""><br class=""></font></div><div class=""><font face="monospace, monospace" color="#3d85c6" class="">&nbsp; &nbsp; func done() {</font></div><div class=""><font face="monospace, monospace" color="#3d85c6" class="">&nbsp; &nbsp; &nbsp; ...</font></div><div class=""><font face="monospace, monospace" color="#3d85c6" class="">&nbsp; &nbsp; }</font></div><div class=""><font face="monospace, monospace" color="#3d85c6" class="">&nbsp; }</font></div><div class=""><br class=""></div><div class="">When you look at code samples online or when I'm reviewing code of colleagues this seems a real issue. A lot of people probably aren't aware of the vast amounts of memory that will never be released (until their apps start crashing). I see people just adding <font face="monospace, monospace" color="#3d85c6" class="">self.</font>&nbsp;to silence the complier :(</div><div class=""><br class=""></div><div class="">I'm wondering what can be done to make this easier for developers. Maybe introduce a 'guard' keyword for closures which skips the whole closure if the instances aren't around anymore. Since guard is a new keyword in this context it shouldn't break any code?</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp;<font face="monospace, monospace" color="#3d85c6" class="">DispatchQueue.main.async { [guard self] in</font></div><div class=""><font face="monospace, monospace" color="#3d85c6" class="">&nbsp; &nbsp; self.updateSomePartOfUI()</font></div><div class=""><font face="monospace, monospace" color="#3d85c6" class="">&nbsp; }</font></div><div class=""><br class=""></div><div class="">I don't have any ideas yet for a better way to pass functions as closures.</div><div class=""><br class=""></div><div class="">- Yvo</div></div></span>
______________________________<wbr class="">_________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a><br class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" target="_blank" class="">https://lists.swift.org/<wbr class="">mailman/listinfo/swift-<wbr class="">evolution</a><br class=""></div></blockquote></div><br class=""></div></blockquote></div><br class=""></div></div></div>
</div></blockquote></div><br class=""></body></html>