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

David Turnbull dturnbull at gmail.com
Sun Jan 17 15:31:26 CST 2016


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



On Sun, Jan 17, 2016 at 11:57 AM, Jacob Bandes-Storch via swift-users <
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> wrote:
>
>> There's a test case demonstrating what I'm about to talking about:
>> 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
>>
>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20160117/38b449e4/attachment.html>


More information about the swift-users mailing list