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.
Related
I came across a tutorial from raywenderlich were the author gave some good tips on handling threading issues in singleton. But when using closures from within the singleton class he is using 'weak' reference cycle. Is it really required so since the class is a singleton, it should have a single instance always right?
final class PhotoManager {
private init() {}
static let shared = PhotoManager()
private var unsafePhotos: [Photo] = []
let concurrentPhotoQueue = DispatchQueue(label: "com.jeesson.googlypuff.photoQueue", attributes: .concurrent)
var photos: [Photo] {
var photoCopy:[Photo]!
concurrentPhotoQueue.sync {
photoCopy = self.unsafePhotos
}
return photoCopy
}
func addPhoto(_ photo: Photo) {
// Do we need 'weak self here.. and why?
concurrentPhotoQueue.async(flags: .barrier) {[weak self] in
// 1
guard let self = self else {
return
}
self.unsafePhotos.append(photo)
DispatchQueue.main.async { [weak self] in
//self?.postContentAddedNotification()
}
}
}
}
The tutorial
In case of DispatchQueue closures don't add any capture list at all, nowhere.
DispatchQueue closures don't cause retain cycles because self doesn't own them.
Basically capture lists inside a singleton object are not needed as the singleton is never going to be deallocated.
Some singleton's lifecycle is tied to App lifecycle. Some singleton's lifecycle is tied to login/logout.
So what if the singleton is to be deallocated upon logout? I think that's a valid case where using [weak self] can be useful, even for a singleton.
Otherwise just as vadian said, DispatchQueue closures don't cause retain cycles because self doesn't own them. For more see here
When we pass an instance of an object as an argument to a method, which is defined inside that object like in the code below, does it create a retain cycle?
self.someMethod(self)
If you reference an instance method of your class:
class FooBar {
func foo() {
print("Foo")
}
func bar() {
self.foo()
}
}
The "self" is implied, and the compiler doesn't need it. Even if you use foo() without the self., it still references self implicitly.
No there is no retain cycle, since you are calling from one instance method to another instance method on the same object.
EDIT:
Where self gets you in trouble is in "escaping" closures. An escaping closure is a closure that is passed to another object that takes a strong reference to it. Completion handlers are usually escaping closures.
So, when you call a function that takes a completion handler and that completion handler is an escaping closure, the other object takes ownership of the closure.
Now, if the closure uses self, it means the closure also owns "self"
typealias completionHandler = () -> ()
class AClass {
lazy var someOtherObject = SomeOtherObject()
var value: Int = 0
func callClosure() {
someOtherObject.doSomething(completion: {
self.foo = self.foo + 1
}
}
}
class SomeOtherObject {
var myCompletionHandler: () -> ()
func doSomething( completion: #escaping completionHandler) {
myCompletionHandler = completion
//pretend there is code here to call an async method and invoke completion
}
}
The above use of self does cause a retain cycle. Here's how:
And instance of AClass creates an object of type SomeOtherObject and keep a strong/owning reference to it. The SomeOtherObject won't go away as long as the instance of AClass lives.
When we call callClosure(), we pass in a completion handler. The SomeOtherObject takes ownership of the closure.
Now, since the code of the closure references self, the closure takes ownership of self. We now have a 3-way retain cycle between the AClass object, which owns the SomeOtherObject, the SomeOtherObject, which owns the closure, and the closure, which owns the AClass object.
You can fix the retain cycle by adding a "capture list" to the closure. That is a list of variables that the closure uses that should be held weakly. That modified code might look like this:
func callClosure() {
//the `[weak self]` capture list below makes self weak inside the closure
someOtherObject.doSomething(completion: { [weak self] in
///use a guard to map weakSelf to strongSelf if it isn't nil, or return
//if self has been deallocated and is now nil.
guard let strongSelf = weakSelf else { return }
strongSelf.foo = strongSelf.foo + 1
}
}
I have a class object in the controller, and then I have a closure in this object.
I assign a function of the controller to the object's closure, and then the page does not deinit.
How can I solve this problem?
import UIKit
class SecondViewController: UIViewController {
let test = TestObject()
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.white
self.test.select = self.selectButton(index:)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.test.doSomethine()
}
func selectButton(index:Int){
print(index)
}
deinit {
print("deinit")
}
}
import UIKit
typealias selectBtnBlock = (_ index:Int)->()
class TestObject: NSObject {
var select:selectBtnBlock?
func doSomethine(){
self.select!(1)
}
}
This is because your test object's select closure strongly captures your SecondViewController when you do the following:
self.test.select = self.selectButton(index:)
I recommend you do some reading about weak and strong types via Apple's Swift language reference. The "interesting phenomenon" you encountered is called a strong reference cycle.
Essentially, since Swift uses ARC as its memory management model, any object that is referenced by at least one other object else will be kept alive, and its memory not deallocated.
In your case, test has captured its parent SecondViewContoller via the line I mentioned. What that means is you have a situation like the following:
SecondViewController -> (owns) test // since its a member of the class
test -> (strongly captures) SecondViewController // via the assignment
This causes a strong reference cycle between the two, and does not allow ARC to deallocate either.
When it (ARC) tries to free up test, is knows that SecondViewController references it, so it can be freed only if the parent is also freed. When it tries to deallocate SecondViewController, ARC knows that this object is referenced by test.select closure.
Since both have a reference count greater than one, neither will get deallocated.
One way to solve your issue is to write:
self.test.select = {
[weak self] // weakly capture self, this prevents a ref cycle
(i:Int)->() in // a closure that accepts an Int
guard let s = self else { return } // check if self is not nil
s.selectButton(index: i) // finally invoke the required method
}
Another way, similar intent:
self.test.select = { [weak self] i in
self?.selectButton(index: i)
}
The weak keyword in this context is used to tell the Swift compiler that I do not want to keep a strong reference to what I am capturing (self in this case).
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.
Swift Closure will have a strong reference cycle when it refers to self like this example:
class Test {
var name = "Hello"
func doSomething() {
{() -> Void in
self.name = "otherName"
}()
}
}
In the previous example, I created a strong reference cycle so I have to fix it with:
class Test {
var name = "Hello"
func doSomething() {
{[unowned self] () -> Void in
self.name = "otherName"
}()
}
}
Question: If I refer self in a closure do I have to use alway unowned self or are there cases where I have to use weak self?
If I refer self in a closure do I have to use alway unowned self or are there cases where I have to use weak self?
Neither. In most cases, just refer to self normally and do nothing with its memory management. You only have to worry about memory management if there is a danger of a retain cycle, and unless you store the closure somewhere, such as a property of self, there is no such danger.
You can easily prove this by adding a deinit implementation:
class Test {
var name = "Hello"
func doSomething() {
{() -> Void in
self.name = "otherName"
}()
}
deinit {
println("bye")
}
}
Now make a Test instance and immediately release it:
func testTest () {
let t = Test()
}
You see "bye" in the console, proving that the instance was released in good order. There was never any kind of "strong reference cycle" in this code. Your concerns are groundless.
[By the way, you are using the word "closure" wrong. Every Swift function is a closure. If there were a retain cycle issue merely because of using the word self in a closure, every Swift function would be subject to this issue - and clearly that is not the case. The place where weak and unowned self comes into play is in an anonymous function - and only, as I said before, if that anonymous function is itself also retained by self.]