I've got a custom class that uses a DispatchQueue.
class MyCustomClass {
func fetch(fromURL url: URL) {
DispatchQueue.global().async { [weak self] in
// workItem stuff where self? is called
}
}
}
Is the [weak self] necessary? The workItem closure references the instance of MyCustomClass, so I see that strong reference, but does the instance of MyCustomClass keep a reference to the enclosed workItem block that's passed to async()? It seems like it doesn't, so is [weak self] unnecessary in this case?
but does the instance of MyCustomClass keep a reference to the enclosed workItem block that's passed to async()?
Not from this example, no.
However, if the instance of MyCustomClass has a DispatchQueue that was used instead of the global queue, then that would strongly reference the work time until it's completed.
No it's not needed the singleton DispatchQueue.global()
DispatchQueue.global().async
doesn't hold a strong reference to self , GCD doesn't cause retain cycles
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
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.
Do i need to use [weak self] within RXSwift subscribeNext closures?
I have the code:
searchController.searchBar.rx_text.throttle(0.2, scheduler: MainScheduler.instance).subscribeNext { searchText in
self.viewModel.searchForLocation(searchText)
}.addDisposableTo(DisposelBag.sharedDisposelBag.disposeBag)
Do i need to modify it so that there is a [weak self] capture list at the beginning of the closure? Like this:
searchController.searchBar.rx_text.throttle(0.2, scheduler: MainScheduler.instance).subscribeNext { [weak self] searchText in
self?.viewModel.searchForLocation(searchText)
}.addDisposableTo(DisposelBag.sharedDisposelBag.disposeBag)
If the closure is not owned by the class you do not have to use [weak self].
In the case of in-line closures the closure is not owned by the class but by the scope it is in and will be released when the scope is left.
If the closure is passed in it may or may not be owned by the class (a property for example) and it is prudent to use [weak self] incase it is owned by the class.
Yes, you should create a weak capture of self if you access self within the closure and it is possible that self could become nil before the closure is called.
If a closure captures self and then self becomes nil, when the closure is called and attempts to access that self, you’ll get an exception.
Credit to scotteg, he has an example project on GitHub: https://github.com/scotteg/TestRxSwiftClosures
See the DetailViewController in the example.
You can uncomment the other two examples, one at a time, to see the results. The first one doesn’t define a capture list at all, and the second one defines an unowned capture. Run the app and enter some text and tap Done within 5 seconds (there’s a 5-second delay in each closure). The first two examples will result in exceptions being thrown.
The basic rule is this: If the capture (e.g., self) can be set to nil, such as if the instance it references gets deallocated, define the capture as weak. Otherwise, if a closure and a capture within that closure will always refer to each other and be deallocated at the same time, define the capture as unowned.
You'll want to use [unowned self] or [weak self] if there will be a strong reference cycle. Variables inside closures can be "owned" by the closure and will stick around if the closure is, so that's why we do [unowned self] or [weak self].
[unowned self] means self cannot be nil when block gets called.if block gets called and self is nil,then app crash.
[weak self] means self can be nil when block gets called.As a matter of that,you have to handle optional self inside the block.
SO,My quick answer is
1.when you are referring a view model in a view controller block,always use [unowned self] because you can ensure view model always exists in its associated view controller.
2.in other cases,always be alerted when you use self in a block.choose unowned vs weak based on if self can be nil or not.
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.
Having a runtime error when program is compiled, purposefully the instantiation of SomeObject is short lived but the block getting passed captures the reference, doesn't work in playground but shows the error when the program is compiled and run.
Objective is to hold the reference temporarily of short lived objects SomeObject until callback gets completed.
Edit - if I comment [unowned self] inside go it works, as I believe it creates a strong reference, but hopefully no memory leak there??? (the caller object went out of scope anyway). please confirm that I shouldn't use [unowned self] in here.
import Foundation
class SomeObject {
func go() { //i guess problem is here, it can't find self,
anotherObject.asyncCall({ [unowned self] in //works if i comment this
self.complete()
})
}
func complete() { //can't move this routine inside block, part of parent class api
println("received callback after 5 sec")
}
}
class AnotherObject {
var callback: (() -> ())?
init() {}
func asyncCall(callback: () -> ()) {
self.callback = callback
let delay = 5 * Double(NSEC_PER_SEC)
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay))
dispatch_after(time, dispatch_get_main_queue(), { [unowned self] in
self.callback!()
})
}
}
var anotherObject = AnotherObject() //not global object but permanent lived
for i in 1...3 { //can't change here, it's part of API that instantiates my objects
var instance = SomeObject() //short lived objects
instance.go()
}
please confirm that I shouldn't use [unowned self] in here
There's no need to concern yourself with memory management merely because an anonymous function mentions self.
If an anonymous function that mentions self is going to be a property of self, then you have a retain cycle and potential memory leak, and you should concern yourself with memory management. You can easily see whether you have a memory leak by implementing your deinit to log; if it doesn't log when you expect this object to be destroyed, it's leaking. If it is leaking, you might try using [weak self], not [unowned self]. unowned is more convenient but it is usable only in very limited circumstances.
However, I see no evidence that the object that's going to retain the callback is the same object that is referred to in it as self. It looks to me more like the opposite: you seem to be using [unowned self] on every anonymous function, apparently without the slightest knowledge of what you are doing. That is extremely dangerous. You should not interfere with memory management unless you have to and unless you know how to. My advice is that you start by deleting every single unowned in your code. Then implement deinit and see if you have any actual leaking objects. I'm betting that you don't.