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

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.

Related

RxSwift pointfree style avoid retain cycles

Im wondering if i can use pointfree-style using Swift/RxSwift like so:
class MyClass {
private let ageService: Observable<Int> = AgeService()
private let userService: Observable<Bool> = UserService()
func test() -> Observable<Int>{
return userService
.getRandomUser()
.flatMap(self.networkService.ageFromUser)
}
Or should i go always with .. ?
func test2() -> Observable<Int>{
return userService.getRandomUser().flatMap { [weak self] user in
guard let strongSelf = self else { return .empty() }
return strongSelf.networkService.ageFromUser(user)
}
}
When working with closures when you are pointing to self inside closure like in your case of flapmap the retain cycle gets created if you DON'T use [weak/unowned self].
So its developer responsibility to avoid these kind of retain cycles. So whenever you have reference for self inside any closure try to use weak / unowned as per scope. In your case go for second i.e test2 function.
Hope out helps ...!!!

Setting function-scope variable to avoid using a capture list

I have the following class, which uses a closure in one of its methods:
class SomeClass {
let someOtherClassInstance: OtherClass
func performAsyncTask() {
DispatchQueue.global(qos: .background).async { [weak self] in
print("\(self?.someOtherClassInstance)")
}
}
}
I'm wondering if I can also rewrite performAsyncTask as:
func performAsyncTask() {
let instance = self.someOtherClassInstance
DispatchQueue.global(qos: .background).async {
print("\(instance)")
}
}
The main goal is that I can avoid making self weak in the capture list - or rather so that I don't have to access self at all. There seems to be no reference to self in the second version, but is there a possibility that there will be an error when I try to access instance?
That's fine (assuming that self.someOtherClassInstance has no
back references to the SomeClass instance). You can achieve the
same with a capture list:
func performAsyncTask() {
DispatchQueue.global(qos: .background).async {
[instance = self.someOtherClassInstance] in
print("\(instance)")
}
}
The closure captures a strong reference to the
OtherClass instance which is held until it has been executed,
but no reference to self.
Note that the closure accesses instance regardless of whether
the SomeClass instance still exists or not, so the behavior is
slightly different from what your first method does.

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

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.

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.

What is the correct way of use strongSelf in swift?

In Objective-C in non-trivial blocks I noticed usage of weakSelf/strongSelf.
What is the correct way of usage strongSelf in Swift?
Something like:
if let strongSelf = self {
strongSelf.doSomething()
}
So for each line containing self in closure I should add strongSelf check?
if let strongSelf = self {
strongSelf.doSomething1()
}
if let strongSelf = self {
strongSelf.doSomething2()
}
Is there any way to make aforesaid more elegant?
Using strongSelf is a way to check that self is not equal to nil. When you have a closure that may be called at some point in the future, it is important to pass a weak instance of self so that you do not create a retain cycle by holding references to objects that have been deinitialized.
{[weak self] () -> void in
if let strongSelf = self {
strongSelf.doSomething1()
}
}
Essentially you are saying if self no longer exists do not hold a reference to it and do not execute the action on it.
Swift 4.2 🔸
guard let self = self else { return }
Ref: https://benscheirman.com/2018/09/capturing-self-with-swift-4-2/
Ref2: https://www.raywenderlich.com/5370-grand-central-dispatch-tutorial-for-swift-4-part-1-2
another way to use weak selfwithout using strongSelf
{[weak self] () -> void in
guard let `self` = self else { return }
self.doSomething()
}
Your use of strongSelf appears to be directed at only calling the doSomethingN() method if self is not nil. Instead, use optional method invocation as the preferred approach:
self?.doSomethingN()
If you use self in your closure it is automatically used as strong.
There is also way to use as weak or unowned if you trying to avoid a retain cycles. It is achieved by passing [unowned self] or [weak self] before closure's parameters.