Swift: Capture lists don't work with nested functions

Originator:kastansn
Number:rdar://22700750 Date Originated:2015/09/15
Status:Open Resolved:
Product:Developer Tools Product Version:
Classification:Other Reproducible:Always
 
Summary:
Consider the following closure that would create a retain cycle if there wasn't used a capture list:

let object = SomeObject(callback: { [unowned self] in event
    
    switch event {
        .case SomeCase:
            self?.doSomething()
        .case SomeOtherCase:
            self?.doSomethingOther()
    }
}

This is all fine. [unowned self] prevents a retain cycle that would otherwise exist because self owns SomeObject and at the same time self is referenced within the SomeObject's callback closure.

Unfortunately, the capture list doesn't work anymore when referring to self within a nested function inside the closure as the following example shows:

let object = SomeObject(callback: { [unowned self] in event
                
                func innerFunction() {
                    self.doSomething()
                }

                switch event {
                .case SomeCase:
                    innerFunction()
                .case SomeOtherCase:
                    self?.doSomethingOther()
                }
            }

The obvious fix here is of course to spare the nested innerFunction(). But sometimes, for matters of code clarity, it is nice to outsource parts of switch cases into local functions. This isn't possible here because, despite of using a capture list, self isn't unowned in the inner function's scope and therefore still creates a retain cycle.

Version:
Xcode Version 7.0 (7A218) / Swift 2

Notes:
@inline-ing the nested function doesn't work, either.

Comments


Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!