Reputation: 489
Is there such a thing? Is there any difference between the two below? Is one more "correct" than the other?
All objects are properties of self
(let's say a view controller) and have the same lifetime as self
. We can introduce an object with a shorter lifetime than self
, which would be weak
, but the same question applies.
objectOne.doSomething { [unowned self] in
self.objectTwo.finish()
self.tableView.reloadData()
// self.someDelegate?.didFinishSomething()
}
vs
objectOne.doSomething {
[unowned objectTwo = self.objectTwo,
unowned tableView = self.tableView
// weak someDelegate = self.delegate
] in
objectTwo.finish()
tableView.reloadData()
// someDelegate?.didFinishSomething()
}
Apple has this example in their docs:
lazy var someClosure: () -> String = {
[unowned self, weak delegate = self.delegate!] in
// closure body goes here
delegate?.doSomething()
}
In this case, delegate
can have a shorter lifetime than self
, but why not use it like this?
lazy var someClosure: () -> String = {
[unowned self] in
// closure body goes here
self.delegate?.doSomething()
}
Upvotes: 4
Views: 91
Reputation: 489
One of the problems that [unowned objectOne = self.objectOne]
might cause is with lazy var UIViews
and racing conditions: if you aren't careful and the lazy
init gets called from different threads, two instances might end up being created. Furthermore, if your superview.addSubview(objectOne)
call is in the lazy
init, both instances will be added to the superview
, and objectOne
will point to one of the two instances.
Upvotes: 0
Reputation: 13679
Yes, there is an important difference. In the case of the Apple docs, the code alternative you presented:
lazy var someClosure: () -> String = {
[unowned self] in
// closure body goes here
self.delegate?.doSomething()
}
will look up the current delegate
on self
when the closure runs.
In the Apple example version:
lazy var someClosure: () -> String = {
[unowned self, weak delegate = self.delegate!] in
// closure body goes here
delegate?.doSomething()
}
the weak delegate
var in the capture list is copying the delegate
pointer on self
that exists at the time of closure declaration, not execution. So if the value of self.delegate
changes after the closure is declared and is different at the time the closure runs, the Apple version of the closure will have a nil delegate (assumedly since the reference to the old delegate was weak) and do nothing.
So as a general rule, copying values or references in capture lists ([someIdentifier = someProperty]
) is how to use the values or references as they exist at the moment the closure is defined. Whereas declaring weak or unowned self in the capture list ([weak self]
) and then accessing properties on that weak reference ({ self?.someProperty }
) will get the values of the properties as they exist when the closure is executed.
Upvotes: 1