I'm parsing the Swift Language Guide tutorial (from Apple iOS dev library) and for every chapter I create a separate swift file. In each file I create multiple functions where I isolate snippets of code that they provide. Everything worked on until testing the Strong Reference Cycles for Closures. For some reason if the class that contains a closure (for a computed property) is declared inside a function, then the closure cannot see the "self" reference of the enclosing class. Any ideas why ? It works fine if the class is not declared inside a function.
func strongRefClosure() {
class HTMLElement {
let name: String
let text: String?
lazy var asHTML: () -> String = {
if let text = self.text {
return "<\(self.name)>\(text)</\(self.name)>"
} else {
return "<\(self.name) />"
}
}
init(name: String, text: String? = nil) {
self.name = name
self.text = text
}
deinit {
println("\(name) is being deinitialized")
}
}
var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world")
println(paragraph!.asHTML())
}
Looks very much like a bug (or at least, a behaviour of function-local structs/classes I can’t find documented). This works fine:
struct Foo {
let someVal = 5
lazy var someLazy: String = {
return toString(self.someVal)
}()
}
var foo = Foo()
foo.someLazy // string "5"
But this doesn’t:
func outer() {
struct Foo {
let someVal = 5
lazy var someLazy: String = {
// error: use of unresolved identifier 'self'
return toString(self.someVal)
}()
}
var foo = Foo()
foo.someLazy
}
An inner struct inside an outer struct works, though:
struct Outer {
struct Foo {
let someVal = 5
lazy var someLazy: String = {
return toString(self.someVal)
}()
}
var foo = Foo()
}
var outer = Outer()
outer.foo.someLazy
As @JeremyP says, you should file a radar.
For me, I have this bug in XCode 8GM, Swift 3, iOS 10.0.
Buggy:
let permissionStatusHandler = { (status: CKApplicationPermissionStatus, error: Error?) in
switch status {
case .granted:
self.fetchUserRecordID() // Buggy: Use of unresolved identifier 'self'
case .initialState:
self.requestDiscoverability() // Buggy: Use of unresolved identifier 'self'
case .couldNotComplete:
error.then { print(#function, $0.localizedDescription) }
fallthrough
case .denied:
self.iCloud.presentiCloudAlert(for: status)
}
}
Kosher:
var permissionStatusHandler: (CKApplicationPermissionStatus, Error?) -> () { return
{ (status: CKApplicationPermissionStatus, error: Error?) in
switch status {
case .granted:
self.fetchUserRecordID()
case .initialState:
self.requestDiscoverability()
case .couldNotComplete:
error.then { print(#function, $0.localizedDescription) }
fallthrough
case .denied:
self.iCloud.presentiCloudAlert(for: status)
}
}
}
Hope this helps some other soul out there.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With