Here I have some examples for closure strong reference cycles. If I assign a closure to a stored property, I can use a closure capture list to make the captured reference unowned/weak. But if I assign a method to a stored property closure or assign the method to a closure in the outer scope I can not use a capture list.
What can I do to remove the reference cycle in the last two cases?
Example to create and avoid strong reference cycle with capture list with closure only
internal class ClosureClass {
internal let p1: String
internal lazy var p2: () -> String = {
[unowned self] // if you comment this out there is a strong reference cycle
() -> String in
return self.p1
}
internal init() {
self.p1 = "Default value of ClosureClass"
}
deinit {
print("Object with property '\(self.p1)' is being deinitialized")
}
}
print("Test 'Closure with strong reference to self':")
var cc: ClosureClass? = ClosureClass.init()
cc!.p2() // lazy need to call it once, else it will not be initiliazed
cc = nil
Example to create strong reference cycle with closure from method
internal class MethodToClosureClass {
internal let p1: String
internal lazy var p2: () -> String = method(self) // Why not self.method ? Will create a strong reference cycle, but I can not set the reference to weak or unowned like in closures with the closure capture list
internal init() {
self.p1 = "Default value of MethodToClosureClass"
}
internal func method() -> String {
// [unowned self] in
return self.p1
}
deinit {
print("Object with property '\(self.p1)' is being deinitialized")
}
}
print("Test 'Set closure with method intern':")
var m2cc: MethodToClosureClass? = MethodToClosureClass.init()
m2cc!.p2() // lazy need to call it once, else it will not be initiliazed
m2cc = nil
Example to create strong reference cycle with setting closure from method from extern
internal class MethodClass {
internal let p1: String
internal var p2: () -> String = {
return ""
}
internal init() {
self.p1 = "Default value of MethodClass"
}
internal func method() -> String {
// [unowned self] in
return self.p1
}
deinit {
print("Object with property '\(self.p1)' is being deinitialized")
}
}
print("Test 'Set closure with method extern':")
var mc: MethodClass? = MethodClass.init()
var method: () -> String = mc!.method // will create a strong reference
mc!.p2 = method
mc = nil
Output
Test 'Closure with strong reference to self':
Object with property 'Default value of ClosureClass' is being deinitialized
Test 'Set closure with method intern':
Test 'Set closure with method extern':
self.method
instead ofmethod(self)
. Also you don't need to annotate everything asinternal
, that's the default. – Bummermethod
if writingself.
in the property closure case, missing feature or bug, but it gave me the suggestion formethod(self)
when I wrotemeth
. Thanks for pointing out. Interesting thatmethod
is not enough for a property, but it is enough for a variable in outer scope. – Escortself.method
rather than justmethod
is a quirk withlazy
properties – they require an explicit use ofself.
, see for example this Q&A – Bummer