Given the following scenario:
class A {
let closure: () -> Void
init(_ c: @escaping () -> Void) {
self.closure = c
}
}
class B {
let other: A
init(_ o: A) {
self.other = o
}
func run() {
other.closure()
}
}
func create() -> B {
let a = A {
print("access B here")
}
let b = B(a)
return b
}
What would be the best way to implement the create()
function? This is a scenario that I find myself finding over and over. Think of it as a ViewController/ViewModel relationship. I want to create the VC with a VM at init time, and the VM needs a closure at init time too. Everything is fine until you want to use the VC in the closure. The easy solution is to move the closure injection as a property, but then the VM (A in the example) needs to deal with optionals for no reason, from its prespective.
A solution is to declare a force unwrapped optional like this:
var b: B!
let a = A { // retain cycle
print("access B here \(b.other)")
}
b = B(a)
but then you have a retain cycle since B -> A -> closrure -> B
. And here are where the problems start. As soon as you weakify the capture then the value of b
inside the closure is always nil.
var b: B!
let a = A { [weak b] in
print("access B here \(b?.other)") // b is always nil
}
b = B(a)
var b: B!
let a = A { [unowned b] in
print("access B here \(b?.other)") // b is always nil and why I need to unwrap now?
}
b = B(a)
var b: B?
let a = A { // still retain cycle
print("access B here \(b?.other)")
}
b = B(a)
Is there an elegant solution that keeps A and B free of optionals? Am I missing something obvious?
Thanks