[swift-users] retain cycle non-obvious when assigning method to closure

Jordan Rose jordan_rose at apple.com
Tue Jan 19 16:43:26 CST 2016


I agree that there are things we could do to improve this situation. My personal preference would be for "implicit closures" like this to be formed as @noescape, and require you to explicitly write a closure expression if the closure might escape. But any of these suggestions would count as language changes and should thus be discussed on swift-evolution.

Jordan

> On Jan 17, 2016, at 13:31, David Turnbull via swift-users <swift-users at swift.org> wrote:
> 
> Why isn't self unowned by default? Seems like that would fix all kinds of problems including being a novice.
> 
> Here's an example of a case where you need a strong self. Imagine that [unowned self] is the default and the programmer made the mistake of forgetting to use [strong self] .
> 
> class ClosureFactory {
>     let s:String
>     init(_ s:String) { self.s = s }
>     func writeln() -> () -> Void {
>         return {[unowned self] in print(self.s)}
>     }
> }
> let writer = ClosureFactory("hi").writeln()
> writer()
> 
> The program crashes. Wouldn't this be better than having a default that makes it easy to write memory leaks? I'd much rather be fixing a bug in code I wrote 5 minutes ago than 5 months ago. Especially a memory leak.
> 
> -david https://github.com/AE9RB/SwiftGL <https://github.com/AE9RB/SwiftGL>
> 
> 
> 
> On Sun, Jan 17, 2016 at 11:57 AM, Jacob Bandes-Storch via swift-users <swift-users at swift.org <mailto:swift-users at swift.org>> wrote:
> I also noticed this problem with nested functions recently:
> 
>     class Foo {
>         
>         var handler: (() -> Void)?
>         
>         func noop() {}
>         
>         func setup() {
>             // error:
>             handler = { noop() }
>             
>             // no error:
>             handler = noop
>             
>             // no error:
>             func innerFunc() { noop() }
>             handler = { innerFunc() }
>             handler = innerFunc
>         }
>     }
> 
> Jacob
> 
> On Sun, Jan 17, 2016 at 11:06 AM, Joshua Scott Emmons via swift-users <swift-users at swift.org <mailto:swift-users at swift.org>> wrote:
> There's a test case demonstrating what I'm about to talking about: https://gist.github.com/jemmons/6f668006fa2712a84807 <https://gist.github.com/jemmons/6f668006fa2712a84807>
> 
> But here's the nut of it. Given a class like:
> 
> class Foo { 
>   var handler: (()->Void)?
>   func noop(){}
>   ...
> }
> 
> If somewhere in this class I do something like:
> 
> handler = { self.noop() }
> 
> I've created a retain cycle because handler holds a strong reference to a closure which holds a strong reference to self which holds a strong reference to a closure that…
> 
> In fact, my understanding is Swift's requirement that self be called out here explicitly is to highlight this danger. 
> 
> Swift makes it easy to fix the problem with a capture list:
> 
> handler = { [unowned self] in self.noop() }
> 
> So far, so good. But what if I do something daft like assign noop directly:
> 
> handler = noop
> 
> This causes a retain loop for all the same reasons as our original example, but there's no self call-out to warn us of impending doom, and no support for some kind of capture list to fix the issue.
> 
> Is there any possibility of requiring "self" here? As in: "handler = self.noop" for example? And is there any way of specifying how we want self to be retained here?
> 
> 
> Cheers,
> -jemmons
> 
> 
> _______________________________________________
> swift-users mailing list
> swift-users at swift.org
> https://lists.swift.org/mailman/listinfo/swift-users

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20160119/92cc48ae/attachment.html>


More information about the swift-users mailing list