Do away with weak, unowned self
access if you're not mutating self in itself. Capture interested properties of self
in the closure
.
Example:
// 1
let closure = { [weak self] in
self?.navigationItem.rightBarButtonItems = [...]
}
or
// 2
let anotherClosure = { [weak self] in
let identifier = self?.identifier ?? "" // identifier is non-optional in SELF scope.
let request = APIRequest(.../identifier)
request.perform(...) { _ in
}
}
In snippet 1 - the self
is optionally chained. In snippet 2 - identifier
is not optional in the normal self
scope.
But just because the self
is marked weak
it's properties are also needed to chained optionally and results in many optional checks
.
Another clean approach is just capture the interested properties
of self
in closures.
The snippet 1 could be re-written as
let closure = { [navItem = navigationItem] in // could just capture as `[navigationItem] in` also
navItem.rightBarButtonItems = nil // no self access and no ugly optional checks
}
most importantly accessing it through the local scoped navItem
- you'll always get the initial state
of the property you're capturing. Attached a Swift playground
demoing this powerful feature. Check out!
and the snippet 2 could be written as
let anotherClosure = { [identifier] in
let request = APIRequest(.../identifier)
request.perform(...) { _ in ... }
}
Note: If you really need to mutate self
then neccessay closure scoping (weak, unowned
) is needed. This example shows clean way to act on properties of self
.
Another tip when calling functions of self
from inside the closures is to keep a local copy of self before the closure.
func doSomethingWithSelf() {
let localSelf = self
let closure = { [localSelf] in
...
}
}
This way the localSelf
over the closure is destroyed when the function returns control.
You can also send self
as an argument to the closure. This way no capturing/copying is needed. You still can act on self
.
func perform<T: AnyObject>(_ reference: T, closure: @escaping (T) -> Void) {
{ [weak reference] in
guard let strongReference = reference else { return }
closure(strongReference)
}()
}
and at the call site no weak self
is needed since everything is handled inside the function and the weak, strong casting is done in one place only.
At the call site this looks like:
perform(self) { (reference) in
reference.doSometing()
}
No more weak self
dancing and un-neccessary nil
checks. 🎉
Top comments (0)