When we should NOT use neither [weak self] nor [unowned self]? - swift

I've read several discussion on StackOverflow about when we should use [weak self] or [unowned self] in closures.
However, are there any cases when we don't have to use neither of them since Swift doesn't show any error or warning when we're just explicitly using self inside a closure.
For example, should we use weak or unowned here?
UIView.animate(withDuration: 0.3) {
self.view.alpha = 0.0
}

You need to use [weak self] or [unowned self] if your closure can cause a Strong Reference Cycle.
This can occur if you assign the closure to a property of self and you refer to self or a property of self inside the closure itself. Closures are reference types, hence essentially the same rules apply to strong references as if you used normal classes.
As for your example, there is no need for [weak self] or [unowned self], since you don't assign the closure to a variable inside the class to which self refers to, so there won't be a strong reference cycle.
For more information, check out the Strong Reference Cycles for Closures part of the Swift programming language guide. Here is an example from the mentioned link of when a strong reference cycle can be caused by closures:
class HTMLElement {
let name: String
let text: String?
lazy var asHTML: () -> String = {
if let text = self.text {
return "<\(self.name)>\(text)</\(self.name)>"
} else {
return "<\(self.name) />"
}
}
init(name: String, text: String? = nil) {
self.name = name
self.text = text
}
deinit {
print("\(name) is being deinitialized")
}
}
Without [unowned self] in the closure of asHTML, a strong reference cycle will be caused by the closure assigned to asHTML. Changing the implementation of asHTML to the following solves this issue:
lazy var asHTML: () -> String = {
[unowned self] in
if let text = self.text {
return "<\(self.name)>\(text)</\(self.name)>"
} else {
return "<\(self.name) />"
}
}

This is somewhat opinion based, so I'll give my opinion :)
I generally base it on synchronicity. If a closure is Async, the calling instance may no longer exist when the closer is called and therefore [weak self] should be used. If a closure is synchronous, it's unnecessary and capturing a strong reference is fine.
This could be expanded to also include closures where you can reasonably expect your instance to remain valid when it's called (e.g. your View animation case), however be aware this makes an assumption that the closure and your usage of it will remain unchanged, so it could theoretically break at some point in the future. This less safe and makes future maintenance more difficult/dangerous.
In the case of an established and predictable API like UIView.animate, I personally tend to use strong self for the sake of brevity, but that's an evaluation you'll need to do yourself and it depends on the usage.
Also as noted in the comments, this is true of function-closures. Assigning a closure to another variable's property has a different set of issues.
As an aside, I have adopted the approach of weak-reference closures simply calling another method in my Type, e.g.
thing.doSomethingWithAClosure() { [weak self]
self?.doSomething()
}
It simplifies the logic while also enforcing more functional/modular code.

Related

Confusion about where should put the [unowned self]

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:
Case 1
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" : "")
}
}
}
}
}
Case 2
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:
When the outer closure is passed to the handle method
When the inner closure is passed to the 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.

Swift 3: capture strong self in #escaping closure without asynchronous work

There is a protocol with the following declaration:
typealias SuggestionSourceCallback = ([Suggestion]) -> ()
protocol SuggestionSource {
func suggest(_ query: SuggestionQuery, callback: #escaping SuggestionSourceCallback)
}
Two classes implement this protocol. First class obtains suggestions asynchronously (via GCD)
final class FisrtClass: SuggestionSource {
private let queue = DispatchQueue(label: "my.app.queue", attributes: [])
private var lastQuery: SuggestionQuery?
// ...
func suggest(_ query: SuggestionQuery, callback: #escaping SuggestionSourceCallback) {
self.queue.async { [weak self] in
// capturing strong self
guard let strongSelf = self else {
return
}
// referencing self here, for example
guard self.lastQuery == query else {
return
}
// suggestions is a local variable
var suggestions: [Suggestion] = []
// ...
DispatchQueue.main.async {
callback(suggestions)
}
}
}
}
...while second class does it synchronously
final class SecondClass: SuggestionSource {
// ...
func suggest(_ query: SuggestionQuery, callback: #escaping SuggestionSourceCallback) {
// ...
callback(self.suggestions[query])
}
}
My questions are:
should I capture strongSelf in FirstClass's implementation?
should I capture strongSelf in SecondsClass's implementation?
UPDATE
Additional question. Suppose SecondClass has its suggestions as a static let, what pattern in this case would be?
final class SecondClass: SuggestionSource {
static let suggestions: [String: [SuggestionQuery]] = {
// ...
}()
// ...
func suggest(_ query: SuggestionQuery, callback: #escaping SuggestionSourceCallback) {
// ...
callback(self.suggestions[query])
}
}
In SecondClass, there is no need to create a strongSelf variable. Where would you put it? The point is that self is guaranteed not to be nil anyway because you are running within the scope of one of its methods.
The same is true of your additional question, but for a different reason. suggestions is now static, so prefixing with self is a matter of syntax, (I am presuming you meant to also prefix the suggest method with static).
However, in FirstClass, there is a subtle difference between capturing strongSelf and not capturing it.
Because you are using [weak self], self could be nil when you enter that block so you need to check against that anyway. One way is to repeatedly use optional chaining, i.e.:
self?.doSomething()
self?.doSomethingElse()
This is saying:
If I have a reference to self, do something. If I still have a
reference to self, do something else.
By adding a strongSelf variable:
guard let strongSelf = self else {
return
}
strongSelf.doSomething()
strongSelf.doSomethingElse()
...you are saying:
do something and do something else if you have a reference to self,
otherwise do nothing.
So, you guarantee that if the first thing happens, so does the second. The approach you take is going to depend on your application.
Scenario 1 is a good candidate for [unowned self].
In this case if the queue exists, so does self, therefore it is safe to reference self without retaining it.
Note: You should only use unowned when you can be sure that the block's lifecycle is directly tied to the captured variable. In other cases unowned can cause interrmittent crashes (which are really hard to debug).
Also unowned is more performant than weak so should be preferred where it is safe to use either source.
For scenario 2, self is not captured by any block that I can determine so you shouldn't need to worry at all about it.
For the update, you still don't capture self, the closure that defines the suggestions dictionary should be executed as soon as it is called.

I find myself using "if self != nil" a lot because of [weak self] ...is this normal?

Example (in my view controller):
RESTApi.fetchUser() { [weak self] Void in
if self != nil { //the view controller is still here.
self!.items.append(stuff)
self!.whatever
}
}
I notice that I'm using if self != nil immediately, followed by self! everywhere. Is there a better way? I feel like this is against the Swift way.
Note: I use [weak self] because my ViewController could be nil (if the user goes back before the REST Api downloads the data).
Why don't you use if let?
if let unwrappedSelf = self {
unwrappedSelf.items.append(stuff)
...
}
You could also use guard let:
guard let unwrappedSelf = self else { return }
unwrappedSelf.items.append(stuff)
...
Idle you have to use guard which is more idle then the if
guard let strongSelf = self else { return }
strongSelf.items.append(stuff)
If you are just calling methods on self when the closure is invoked, then you don't even need to use if let, guard let, or if self != nil. The below code also works just fine to call the methods if self is not nil, and to do nothing if it is:
RESTApi.fetchUser() { [weak self] in
self?.items.append(stuff)
self?.whatever()
}
This conditional unwrapping is usable in all cases except those where you need to pass self or a property of self as an argument to a non-optional function parameter, or assign self or a property of self to a variable with a non-optional type.
As a broader note, there isn't necessarily a need to make self weak in this scenario anyway. That's usually only needed if self is retaining the closure that references self inside as an ivar (circular reference). In your case, it's RestApi that's holding a reference to the closure, and the view controller that self is referring to would be retained by the closure until the closure returned. At that point, if the view controller had already been dismissed by the user and the closure's reference was the last reference to it, it would then be deallocated after the closure executed (no circular reference).
So making self weak in this example only applies if you specifically want the scenario of dismissing the view controller to deallocate the instance and the closure to then fail to run anything at all.
Simply do this:
guard let `self` = self else {
return
}
self.items.append(stuff)

Referencing [weak self] as self? inside animateWithDuration causes crash

If I declare [weak self] on a closure and reference self as self? inside UIView.animateWithDuration the app will crash:
someFunc() { [weak self] (success) -> Void in
UIView.animateWithDuration(0.25) {
self?.someView.alpha = 1;
}
}
with a message sent to deallocated instance
but if I optionally unwrap self ahead of time it doesn't
someFunc() { [weak self] (success) -> Void in
if let weakself = self {
UIView.animateWithDuration(0.25) {
weakself.someView.alpha = 1;
}
}
}
Why is that, I would think that it doesn't matter which way I reference the weak self since it should "just" optionally unwrap self? correctly. For context this is done in a UICellView which is deallocated when I leave the UICollectionViewController
EDIT: Filed a bug with apple: #23492648
I think the problem here is that self is special. You've passed the reference to self weakly into the anonymous function to prevent a retain cycle, but there isn't really an Optional wrapping self in this story. Thus, the syntactic sugar self?.someView.alpha = 1 — and remember, it is merely syntactic sugar — doesn't work.
It may be that Apple will regard this as a bug; or maybe not. But either way, the solution is to do formulaically exactly what you are doing in the second example: do the weak-strong dance explicitly.

Block retain cycles in Swift?

Traditionally in Objc, we do weakSelf to prevent additional retain count for blocks.
How does swift internally manage retain cycles that occur in blocks for Objc?
To prevent a block from holding a strong reference to an object, you must define a capture list for the block.
The closure expression syntax is defined as follows:
{ ( /*parameters*/ ) -> /*return type*/ in
// statements
}
But this is extended later in the documentation to include a capture list. This effectively equates to the expression syntax being defined as follows:
{ [ /*reference type*/ /*object*/, ... ] ( /*parameters*/ ) -> /*return type*/ in
// statements
}
...where /*reference type*/ can be either weak or unowned.
The capture list is the first thing to appear in the closure and it is optional. The syntax, as shown above is defined as one or more pairs of reference type followed by object; each pair is separated by a comma. For example:
[unowned self, weak otherObject]
Complete example:
var myClosure = {
[unowned self] in
print(self.description)
}
Note that an unowned reference is non-optional, so you don't need to unwrap it.
Hopefully that answers your question. You can read up more about ARC in Swift in the relevant section of the documentation.
You should pay particular attention to the difference between weak and unowned. It could be safer in your implementation to use weak, because using unowned assumes the object will never be nil. This may lead to your app crashing if the object has actually been deallocated before being used in your closure.
Using weak as the reference type, you should unwrap with ?, as follows:
var myClosure = {
[weak self] in
print(self?.description)
}
The only thing that threw me off with capture lists was when to use weak vs unowned.
The book distilled it down to these rules:
If self could be nil in the closure use [weak self].
If self will never be nil in the closure use [unowned self].
See the section Weak and Unowned References in The Swift Programming Language book for a deeper explanation.
As described above there are 2 possibilities to avoid retain cycles in Swift and these are weak and unowned as described below:
var sampleClosure = { [unowned self] in
self.doSomething()
}
where the self never can be nil.
var sampleClosure = { [weak self] in
self?.doSomething()
}
where self need to be unwrapped using ?.
Here there is a important observation to do, if there are more instructions that use self and can be share the results etc, a possible correct way can be:
var sampleClosure = { [weak self] in
if let this = self{
this.doSomething()
this.doOtherThings()
}
}
or
var sampleClosure = { [weak self] in
guard let strongSelf = self else{
return
}
strongSelf.doSomething()
strongSelf.doOtherThings()
}