[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