[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