Swift closures causing strong retain cycle with self - swift

I just want to know if I am understanding this correctly or not. So according to the apple docs when you create a closure as a property of a class instance and that closure references self(The class that created the closure property) this would cause a strong retain cycle an ultimately the class nor the closure will ever get released. So in laymen terms that means that if I have a class that has a property and that property is a closure, and once I assign the functionality of that closure within the class that declares the closure property that will cause a strong retain cycle. Heres a quick example of what I mean
class SomeViewController{
let myClosure:()->Void
public func someFunction(){
....bunch of code
myClosure = {
self.dismiss(blahBlahBlah)
}
}
}
This ultimately causes a retain cycle since the closure keeps a strong reference to self, which is the class that creates the closure property. Now to fix this according to apple I would define a capture list like so
class SomeViewController{
let myClosure:()->Void
public func someFunction(){
....bunch of code
myClosure = { [weak self] in
self?.dismiss(blahBlahBlah)
}
}
}
Notice how I put the [weak self] before the in statement. This lets the closure know to only hold a weak reference to self and not a strong reference. IM supposed to use weak when self can out live the closure or unowned when the closure and self live for the same duration.
I got this information from here Automatic Reference Counting and in the Strong Reference Cycles for Closures section of that link, theres this sentence "A strong reference cycle can also occur if you assign a closure to a property of a class instance, and the body of that closure captures the instance" Im about 90% sure Im understanding this correctly but theres just that 10% of doubt. So do I have this correct?
The reason why im asking this is because I use callbacks for some of my buttons in my views. And those callbacks call to self but the self in that scenario is the view controller that is responding to the callback not the actual view itself. This is where im doubting myself because I from that sentence I highlighted I don't think I need to put [weak self] on all those button callbacks, but im just making sure. Heres an example of this
class SomeViewController {
let someSubview:UIView
override viewDidLoad() {
//Some Subview has a button and in that view I just have some action that gets fired off calling the callback here in the view controller I don't need to use the [weak self] in this scenario because closure property is not in this class correct?
someSubview.someButtonsCallback = {
....run code then
self?.dismiss(blahBlahBlah)
}
}

Yes, that can still cause a retain cycle.
The simplest retain cycle is 2 objects that each have strong references to each other, but 3-way and larger retain cycles are also possible.
In your case, you have view controller who's view contains a button (a strong reference.) The button has a strong reference to a closure. The closure strongly references the view controller using self. So the view owns the button. The button owns the closure. The closure owns the view controller. If you dismiss the view controller (say it was a modal) then it SHOULD be deallocated. However, since you have this 3-way retain cycle, it won't be deallocated. You should add a deinit method to your view controller with a print statement and try it.
The solution is to add a capture list (The [weak self] bit) just like you did in your first example.
Note that a common pattern is to add a capture list, and then map the weak variable to a strong variable inside the closure:
let myClosure = { [weak self] in
guard let strongSelf = self else { return }
//...
strongSelf.doSomething()
}
That way, if the closure is still active but the object that owns it was released, the guard statement at the beginning detects that self is nil and exits at the beginning of the closure. Otherwise you have to unwrap the optional every time you refer to it.
In certain cases it's also possible that the object in the capture list (self in these examples) could be deallocated in the middle of the closure being executed, which can cause unpredictable behavior. (Gory details: This is only when the closure is run on a different thread than the owner of the object in the capture list, but completion handlers are pretty commonly run on a background thread, so it does happen)
Imagine this:
let myClosure = { [weak self] in
self?.step1() //1
//time-consuming code
self?.property = newValue //2
//more time-consuming code
self?.doSomething() //3
//even more time-consuming code
self?.doSomethingElse() //4
}
With the code above, if the closure is run on a background thread, its possible that self would still be valid at step 1, but by the time you execute step 2, self has been deallocated. The same goes for steps 3 and 4. By adding the guard strongSelf = self else { return } at the beginning of the closure you test at the entry of the closure to make sure self is still valid, and if it is, you make the closure create a strong reference that only lives as long as the closure takes to run, and that prevents self from being deallocated while the closure code is executing.)

Related

How Unowned reference works with capture variables in Swift

There are a lot of tutorials on ARC. But I am not understanding the clear working of unowned or weak as how the reference captured variables becomes null.
Apple Document :
Define a capture in a closure as an unowned reference when the closure
and the instance it captures will always refer to each other, and will
always be deallocated at the same time.
class RetainCycle {
var closure: (() -> Void)!
var string = "Hello"
init() {
closure = { [unowned self] in
self.string = "Hello, World!"
}
}
}
the closure refers to self within its body (as a way to reference self.string), the closure captures self, which means that it holds a strong reference back to the RetainCycle instance. A strong reference cycle is created between the two. By unowned its breaking reference cycle.
But I want to understand which scenario both will not be mutually deallocated at the same time and Unowned self becomes null just want to crash it.?
As I get, You ask How self can be null while closue is running. If I get this right I can give you a quite similar example this that I have seen before.
I wrote an extension to UIImageView that download image from given link and set itself like this.
public extension UIImageView{
func downloadImage(link: String){
let url = URL(string:link)
URLSession.shared.dataTask(with: url){ [unowned self]
if let image = UIImage(data: data){
DispatchQueue.main.async{
self.image = image
}
}
}
task.start()
}
}
But there was a problem. Downloading an image is a background task. I set completion method to UrlSession and increased its reference count. So, my closure remains even if imageView is deaollecated.
So What happens if I close my viewController that holds my UIImageView, before download completed. It crashes because of imageView is deallocated but closure still remains and tries to reach its image property. As I get, you want to learn this.
I changed unowned reference to weak to solve this problem.
which means that it holds a strong reference back to the RetainCycle instance
This isn't true. It has an unowned reference back to the RetainCycle instance. That's not the same thing as a strong reference.
But I want to understand which scenario both will not be mutually deallocated at the same time and Unowned self becomes nilI just want to crash it.?
Any time closure is captured by something outside of RetainCycle, and so outlives its owner:
var rc: RetainCycle? = RetainCycle() // create an RC
let cl = rc?.closure // Hold onto its closure
rc = nil // Deallocate the RC
cl?() // Access the closure safely, but its reference to `self` is invalid. Crash.
As a rule, closures that involve unowned self should be impossible to reference outside of self. It's sometimes difficult to know this is true. For example, here is a case that recently crashed an app I work on:
var completion: (() -> Void)?
...
DispatchQueue.main.async { [unowned self] in
self.completion()
self.completion = nil
}
This feels fine, but if self is deallocated between the time it enqueues the main-queue block and the time that block runs, boom.
BTW, in this case the right answer would be a regular, strong self. We want the retain loop to keep this object around until its completion handler runs, at which point the block goes away, the reference to self goes away, and self is properly deallocated. So [weak self] is not always the answer, either.

Will this cause a retain cycle Swift?

I have this code and I'm questioning if I need to use a capture list to make my reference to self weak.
Right now I'm thinking that getTextFileData and .main.async are static methods, therefore, this will not cause a retain cycle. However, I do access the games property, kinda not sure.
NPWebService.getTextFileData { (games, success) in
if success {
self.games = games
DispatchQueue.main.async {
self.updateUI()
}
}
}
This wouldn’t cause a retain cycle because it looks like a static method on a different type. So the getTextFileData method will temporarily retain the closure you are passing in until any asynchronous work is complete, and the closure will temporarily retain self. But when the work is complete and the closure is done executing, those temporary retains will expire and automatic memory management can clean up as appropriate.
The danger of a retain cycle is when you have a closure the that references / captures self, and self also retains the closure, for example. Like this:
class GameController {
var games: [Game]?
// self retains the closure as a property
let updateClosure:([Game], Bool)->() = {
games, success in
if success {
self.games = games // and the closure captures self. Each retains each other indefinitely, this is a retain cycle and neither this closure nor self will ever be deallocated
}
}
func load() {
NPWebService.getTextFileData(updateClosure)
}
}
So normally weak self or unowned self in closure capture lists are only needed:
if self or something retained by self will be retaining that closure (this is rarely the case when a closure is created locally and transiently at the call site to pass into a method as an argument)
if for non-retain cycle reasons, the desired behavior is to allow self to be deallocated before some asynchronous work is completed, and before the closure is invoked. In this case the closure shouldn’t strongly capture self and instead should weakly capture it and check if it still exists before making use of self when the closure is invoked

Captured weak reference pointed to wrong object

If I weakly reference self in a closure:
{[weak self] in self!.doSomethinmg()}
And self is deallocated, yet the closure continues to exist. Is it possible that self in the closure can become non-nil at some point in the future -- pointing to some random new object as determined by the runtime environment?
A pointer is a variable whose value is a memory address. The same is
true for a weak pointer, but the value of a weak pointer is
(due to some runtime magic) set to nil if the pointed-to object is
deallocated. It is irrelevant if any new object is created at the
same memory location later, the weak pointer variable stays nil.
So
{ [weak self] in /* ... */ }
creates a closure with a weak pointer variable. That variable
is set to nil when the pointed-to object is deallocated.
That may happen before the closure is called or during the execution
of the closure, so even
{ [weak self] in
if (self != nil) self!.doSomethinmg()
}
is unsafe and can crash if the object is deallocated between the test
and the method call.
But at any point, the weak pointer either points to
the original object instance or is nil. It will
never point to some other object instance. (That may happen with
unowned references.)
As Lorenzo says, don't
force unwrap the weak pointer. Either use optional chaining or
create a strong reference inside the closure.
It depends on what you want to achieve.
Martin is suggesting the right thing. In order to guarantee you don't have any crash and continue to deal with that instance you can use weak/strong dance. Otherwise, use self?.
So for example, with the weak/strong dance you can do the following:
{ [weak self] in
if let strongSelf = self {
strongSelf.doSomething()
}
}
Otherwise
{ [weak self] in
self?.doSomething()
}
While in the first case the instance that belongs to self will continue to exist until the closure will be discarded, in the second case, instead, since the instance will be put to nil, it will behave as a sort of non-op.
If all the strong references to an instance are removed, then the instance will eventually be deallocated. But that doesn't necessarily mean the references that were referring to it will be reused. All the strong references are obviously gone because they had to be in order for it to be deallocated in the first place. So whatever that means for the memory that those references required for their referring duties is irrelevant to the application, because the references don't exist anywhere in it anymore.
Which leaves unowned and weak references left. Apple makes it pretty clear that attempting to access the value of an unowned reference after the instance has been deallocated is a no, no:
If you try to access the value of an unowned reference after that instance has been deallocated, you’ll get a runtime error.
So that is also irrelevant to the application, simply because it's a hard-rule not to be broken.
Which leaves, last but not least, weak references. Apple says this about weak references:
Because a weak reference does not keep a strong hold on the instance
it refers to, it’s possible for that instance to be deallocated while
the weak reference is still referring to it. Therefore, ARC
automatically sets a weak reference to nil when the instance that it
refers to is deallocated.
...
You can check for the existence of a value in the weak reference, just
like any other optional value, and you will never end up with a
reference to an invalid instance that no longer exists.
The key take away here is that the reference is set to nil. And even though nil represents nothing, it's still a valid value. And I feel it may be safe to assume that the runtime environment won't steal a reference and use it for another purpose when it's still pointing to a valid value. Imagine what it'd be like otherwise.
So the relevance to the application here for weak references is just that they may become nil at some point; and as #MartinR showed in his answer, this may even happen mid-execution of the closure. So the final solution would seem to be creating a strong reference from the weak reference before using it, aka the "weak/strong dance":
Either:
{ [weak self] in
if let strongSelf = self {
strongSelf.doSomething()
}
}
or
{ [weak self] in
guard let strongSelf = self else { return }
strongSelf.doSomething()
}
If the closure consists of a single optional chain:
{ [weak self] in
self?.doSomething()
}
will simply result in a non-op if self is nil, but no idea if this bears any guarantee that self won't be deallocated mid-execution of the closure if it's arbitrarily longer:
{ [weak self] in
self?.doSomething()
...
self?.doSomethingDownTheLine()
}
So in this case, doing the weak/strong dance will guarantee that your closure will be all-or-nothing:
{ [weak self] in
guard let strongSelf = self else { return }
strongSelf.doSomething()
...
strongSelf.doSomethingDownTheLine()
}

Is method closure retaining the instance in swift?

In swift, I can use instance methods as closures, for example, assigning the method to a callback
self.someView.someCallback = self.doSomething
So, is self strongly referenced here in self.doSomething? Does the line above create a reference loop?
There are two possible scenarios based upon your code snippet:
If doSomething is a instance method of self, then, yes, that line establishes a strong reference. Remember that Closures are Reference Types. You can easily confirm this and is easily confirmed empirically. Consider:
class ViewController: UIViewController {
var foo: (() -> Void)?
override func viewDidLoad() {
super.viewDidLoad()
foo = bar
foo?()
}
func bar() { ... }
}
If I present and dismiss this view controller three times, and then use Xcode’s “Debug Memory Graph”, , I will see those three instances still lingering in memory (on the left) and if I select one, it will show me the strong reference cycle visually in the center panel:
And because I used the “Malloc stack” feature, on the right panel I can see precisely where the lingering strong reference is, namely in viewDidLoad where I set that closure.
However, if doSomething is not a function, but rather is a closure, then that line, itself, does not establish a strong reference, but rather it becomes a question of whether the closure, itself, refers to self and, if it does, whether there is a [weak self] or [unowned self] capture list or not. For more information, see Strong Reference Cycles for Closures.
In order to have a retain cycle, you need to have a strong reference on each direction, i.e.:
Object A strongly references Object B
Object B strongly references Object A
Assuming self in the code you shared is a View Controller, and assuming someView is a strong reference to a view, we could say that:
Object A (View Controller) strongly references Object B (Some View)
Now if Object B (Some View) has a strong reference back to the View Controller, you will have a retain cycle.
Assuming doSomething is a method in your ViewController, and not a closure, you will have a retain cycle
An easy way to check this, is by implementing deinit in both your Some View and your View Controller, like so:
class SecondViewController: UIViewController {
var someView: CustomView?
override func viewDidLoad() {
super.viewDidLoad()
someView = CustomView(frame: view.frame)
someView?.someCallback = doSomething
}
func doSomething() {
}
deinit {
print(#function)
}
}
final class CustomView: UIView {
var someCallback: (() -> Void)?
deinit {
print(#function)
}
}
You will see that the prints on deinit are never printed out in the console. However changing the way you assign someCallback to:
someView?.someCallback = { [weak self] in
self?.doSomething()
}
will cause deinit to run, thus breaking the retain cycle
Edit:
Or even, as an alternative:
weak var weakSelf = self
someView?.someCallback = weakSelf?.doSomething
(Even though this is using a weak reference, because this expression is evaluated at the time the assignment of someCallback is performed, not at the time it is executed, this will still become a strong reference) - Thanks #Rob
In Swift, declare a closure type variable, and would like to assign a func to it, prevent from the retain issue,
just do as follow, search the answer for all day long, eager to share:
self.someView.someCallback = {
[unowned self] in self.doSomething()
}

'[weak self]' in RXSwift closures

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.