I have a retained cycle so my viewcontroller's deinit won't be called, and I'm trying to resolve this my adding [unowned self], but I'm not too sure where to put the unowned in my cases:
class YADetailiViewController: UIViewController {
var subscription: Subscription<YAEvent>?
override func viewDidLoad() {
super.viewDidLoad()
if let query = self.event.subscribeQuery() {
self.subscription = Client.shared.subscribe(query)
self.subscription?.handle(Event.updated) {
query, object in
DispatchQueue.main.async {
[unowned self] in// Put unowned here won't break the cycle, but it does compile and run
self.pageViewLabel.text = String(object.pageViews) + " VIEW" + ((object.pageViews > 1) ? "S" : "")
}
}
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
if let query = self.event.subscribeQuery() {
self.subscription = Client.shared.subscribe(query)
self.subscription?.handle(Event.updated) {
[unowned self] query, object in // Put unowned breaks the cycle, and deinit is called
DispatchQueue.main.async {
self.pageViewLabel.text = String(object.pageViews) + " VIEW" + ((object.pageViews > 1) ? "S" : "")
}
}
}
}
I'm curious what's the differences between these two scenarios and why one works but not the other
Indeed, as correctly mentioned by @matt the problem is related to the time when self
is captured. In fact int this code self
is captured twice:
handle
method async
method (during the handle
closure execution)The outer closure needs self
to pass it to the inner closure, otherwise the inner closure won't be able to capture it.
The nature or retain cycle is the following: self
(YADetailiViewController) -> subscription
-> closure (handle
parameter) -> self
. To break this cycle it's enough to not retain self
in that (outer) closure. That's why the second code sample works.
The second capture of self
(in the inner closure) happens only when the outer closure is executed and lasts until that async
block is executed - usually it's quite a short time.
In the first code sample you're not breaking the cycle. The second capture of self
doesn't happen but the first one (causing thy cycle) is still present.
And if your handle
closure can still be called when the view controller is already deinited/released then as suggested by @AdrianBobrowski you should use weak
instead of unowned
to prevent possible crash.
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