Imagine the following scenario using Manual Memory Management (aka non-ARC):
I have a VC that passes a block to a class method. Before the block being executed, the VC is popped up out of a UINavigationController. A weak reference in the form of __block MyVC *weakSelf = self is passed to the block which is then converted to MyVC *strongSelf = weakSelf (aka weak/strong dance). The block is never retained by any of the intervenients.
In this scenario, what I am seeing in my code is:
The dealloc of the VC is called when it is popped out.
The block is eventually is called.
The app crashes because I am accessing garbage (the strongSelf is pointing to it).
My question is: I don't want my VC to stay alive until the block eventually executes, but once the block is executed I want to confirm that strongSelf is valid.
I have checked this (non-trivial example by Apple) which doesn't work because it's designed with ARC in mind. So how can I have the same behaviour with MMM? Ideally I want to have what __weak does: if the retainCount reaches zero, I want its references to point to nil and not to garbage.
After reading this from Apple:
In some cases you can use __unsafe_unretained if the class isn’t
__weak compatible. This can, however, become impractical for nontrivial cycles because it can be hard or impossible to validate
that the __unsafe_unretained pointer is still valid and still points
to the same object in question.
Since I don't have access to __weak what I want to do is even possible?
I battled with this exact issue back in the iOS 4.x days. It's not easy without weak pointers giving you a hand!
If you are guaranteed that block is executed on the main thread at a later point (i.e. where strongSelf is assigned from weakSelf) then you basically need a place to store a "isDead" flag, which you set when the VC is dealloced. You then check this flag before doing anything with weakSelf/strongSelf. One solution is this:
You need a class who's only job is to store this "isDead" flag in a member variable. Something like a NSMutableBoolean. I won't write one out, it's simple enough, it just needs a single BOOL property.
In your VC's -[NSObject init] method you create an instance of this flag object, which should initially be set to false.
You then pass this object through to any block you queue for later execution, such that it is automatically retained/released by the block (i.e. without going through the weak/strong dance). Inside the block, you check if the flag is still NO before doing anything with weakSelf.
The key of course is to set the flag to YES inside the VC's -[NSObject dealloc] method, and then release it. If any blocks are still pending execution, they will have already retained the flag object themselves, and when they are later executed they will query the flag discover that the VC is now dead.
This sounds cumbersome (and it is, a bit) but the idea is that the "isDead" flag lives outside the scope of the VC and is therefore not tied to it's lifetime. As for thread safety, as long as you only set/query the flag inside the VC's init/dealloc method and when the block is executed (on the main thread, not on a background thread) it will be thread safe.
I don't want my VC to stay alive until the block eventually executes
But why does it matter? The memory of one VC shouldn't be that much, and if the block performs any UI actions on the VC, that's okay too, since the VC isn't displayed anyway.
Basically, the block should not capture a weak reference to the VC if the VC doesn't retain the block. Using non-zeroing weak reference means you guarantee that the object will stay alive, which is not the case here. I would suggest you not do this weak thing.
Related
This question already has an answer here:
How can I create a reference cycle using dispatchQueues?
(1 answer)
Closed 2 years ago.
Help me resolve a tiny argument with a colleague. Weak self is not needed in this circumstance, right?
(He doesn't believe me)
__weak auto weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf _someHelper];
});
Correct, it is not always needed in cases like this. We often wouldn’t bother with this syntactic noise in this situation.
If it was dispatch_after or if this dispatch back to the main queue was buried inside some asynchronous call, then there’s an argument for weakSelf pattern (so you don’t keep strong reference longer than might be needed), but in your simple example, dispatching immediately to the main queue, the weak reference to self is not needed.
That having been said, it’s not wrong to adopt weakSelf pattern here. Just unnecessary.
The question in my mind is that if you’re dispatching back to the main queue, that suggests you are in the middle of something time consuming on some background queue. In that case, then refraining from keeping strong reference to self may well be prudent. We can’t say without seeing the broader context of where you are performing this code.
Note that ARC (automatic reference counter) can lead to situation where strong references will create a cycle. Such cycle will lead to memory leak (reference counter will never reach zero). In languages where garbage collection is available such cycle can be detected by gc and memory will be freed.
Now weak pointer prevent creation of permanent cycle of strong references.
Presented example is to general to tell if this is necessary or not.
There are some cases where some other object is responsible for object lifetime and invocation of _someHelper should be prevented when strong referees from other objects has expired (for example there action is not needed any more). In this case you need weak self.
In other case you need warranty that _someHelper is executed even if all other objects has lost contact with this object, so in such case you need that dispatch queue holds strong reference to object. In this case weak self is obsolete.
Background
Our app has a class that attempts to implement the Receptionist Pattern for KVO observation. Other classes throughout the app (such as view controllers) create instances of this one Receptionist class to serve as the KVO observer. Each Receptionist instance keeps a copy of a block provided by the owner, which the Receptionist instance will invoke on the proper operation queue when a KVO notification arrives.
The Receptionist's dealloc method invokes the KVO removeObserver method. The Owner keeps the Receptionist instance as a strong-reference field, so when the Owner is deallocated, the Receptionist will remove itself as an observer in the process of being deallocated.
The Crash
We're seeing reports from the field of crashes when the KVO notification is received by a Receptionist instance on one thread while the same instance's dealloc is in progress on another thread. The Receptionist's implementation of observeValueForKeyPath:ofObject:change:context: is crashing on this line:
__weak typeof(self) weakSelf = self;
The stack trace in the crash report shows this as a call to objc_initWeak, which calls weak_register_no_lock, which calls _objc_fatal.
The object whose key is being observed by this particular Receptionist is never deallocated. The Owner is also not being deallocated; the Owner is replacing this Receptionist instance with a different one.
The Confusion
I can understand that it's not useful to create a weak reference to an object that's already being deallocated, but I would expect weakSelf to receive a nil value, not to cause a crash.
The documentation for objc_initWeak explicitly mentions setting the target to null if the argument to which the reference is desired has begun deallocation. That sounds like the desired behavior, but I don't think it's what I'm seeing. I'm not keen to replace that line with an explicit call to objc_initWeak, since I doubt I'd manage the deallocation properly.
Could it really be the Receptionist's responsibility to notice that its own deallocation is in progress before requesting a weak reference to self? I would assume that there's some window between when an NSObject's deallocation starts and when that object's dealloc method is called, so signalling within the object from the dealloc method sounds flaky.
Thank you for reading!
PS: heavily edited after reading the questions raised by Ken Thomases.
This has nothing to do with the creation of the weak reference. The line you cite should only be run in a context where something has a strong reference to self.
Think about it: the crash that you're seeing may be during that line within your observeValueForKeyPath:ofObject:change:context: implementation, but, since there's clearly a race between deallocation and the call of that method, the deallocation could also occur during dispatch of that method call (or some other point). You're vulnerable to different crashes. So, no changes to the implementation of the method could possibly fix the problem, since the problem could manifest before your method is even called.
It's your responsibility to keep a strong reference to an object if you're going to be calling methods on that object. Or, from the other perspective, to avoid calling methods on object pointers that you're not sure will live for the duration of the call (because you hold a strong reference or some other API guarantee).
With KVO, you need to remove observers before releasing your last strong reference.
I'm working with network request classes and I'm concerned about crashes. For instance, working with closures is really easy as you pass a callback method to a function:
// some network client
func executeHttpRequest(#callback: (success: Bool) -> Void) {
// http request
callback(true)
}
// View Controller
func reload() {
networkClient.executeHttpRequest() { (success) -> Void in
self.myLabel.text = "it succeeded" // NOTE THIS CALL
}
}
However, since the process that should execute the callback is async, when callbacks interact with container class element (in this case an UIKit class) it may be vulnerable to crashes in situations like
The user navigated to another View Controller while the async task was still executing
The user pressed the home button while the async task was still executing
Etc...
So, when the callback finally gets fired, self.myLabel.text might result in a crash, as the View Controller to whom self was refering could already be deallocated.
Up to this point. Am I right or do swift implement something internally so that this never happens?
If I am right, then here's when the delegate pattern comes in handy, as delegate variables are weak references, which means, they are not kept in memory if deallocated.
// some network client
// NOTE this variable is an OPTIONAL and it's also a WEAK REFERENCE
weak var delegate: NetworkClientDelegate?
func executeHttpRequest() {
// http request
if let delegate = self.delegate {
delegate.callback(success: true)
}
}
Note how self.delegate, since it is a weak reference, it will point to nil if the View Controller (who implements the NetworkClientDelegate protocol) gets deallocated, and the callback is not called in that case.
My question would be: do closures have anything special that makes them a good choice in scenarios similar to this one, rather than going back to delegate pattern? It would be good if examples of closures (that won't end up in crashes due to nil pointer) are provided. Thanks.
So, when the callback finally gets fired, self.myLabel.text might result in a crash, as the View Controller to whom self was referring could already be deallocated.
If self has been imported into the closure as a strong reference, it is guaranteed that self will not be deallocated up until the closure has been finished executing. That is, the view controller is still alive when the closure gets called - even if it's view is not visible at this time. Statement self.myLabel.text = "it succeeded" will be executed, but even the label will not be visible, it will not crash.
There is, though, a subtle issue which can lead to a crash under certain circumstances:
Suppose, the closure has the last and only strong reference to the view controller. The closure finishes, and subsequently gets deallocated, which also releases the last strong reference to the view controller. This inevitable will call the dealloc method of the view controller. The dealloc method will execute on the same thread where the closure will be executed. Now, that the view controller is a UIKit object, it MUST be guaranteed that all methods send to this object will be executed on the main thread. So, IFF dealloc will be actually executed on some other thread, your code may crash.
A suitable approach would require to "cancel" an asynchronous task whose result is no longer needed by the view controller when it is "closed". This, of course, requires that your "task" can be cancelled.
To alleviate some issues with your former approach, you might capture a weak reference of your view controller instead of a strong reference when defining the closure. This would not prevent the asynchronous task to run up to its completion, but in the completion handler you can check whether the view controller is still alive, and just bail out if it does not exists anymore.
And, if you need to "keep" an UIKit object in some closure which may execute on some arbitrary thread, take care that this might be the last strong reference, and ensure this last strong reference gets released on the main thread.
See also: Using weak self in dispatch_async function
Edit:
My question would be: do closures have anything special that makes them a good choice in scenarios similar to this one, rather than going back to delegate pattern?
I would say, closures are the "better" approach in many use-cases:
Delegates are more prone to issues like circular references than closures (since they are "owned" by an object, and this object might be captured as a variable in the delegate).
The classic use-case for closure as completion handlers also improves the "locality" of your code making it more comprehensible: you state what shall happen when a task finished right after the statement invoking the task - no matter how long that may take.
The huge advantage with closures versus regular "functions" is that a closure captures the whole "context" at the time when it is defined. That is, it can refer to variables and "import" them into the closure at the time when it is defined - and use it when it executes, no matter when this happens, and when the original "stack" at definition-time is gone already.
If I were you I would use closures since they are more convenient and flexible than delegation in this scenario.
Regarding the user navigating to other view controllers and the async operation still executing in the background you could keep a reference to those operations and whenever the user navigates away from the view controller you could cancel them.
Alternatively, you could verify if the view controller's view is visible before updating the UI:
viewController.isViewLoaded && viewController.view.window
Regarding the app entering background/foreground, you could pause/resume the operations by overridng the applicationDidEnterBackground and applicationWillEnterForeground or registering for the appropriate notifications: UIApplicationWillEnterForegroundNotification / UIApplicationDidEnterBackgroundNotification
I highly recommend you to use AFNetworking since it's API offers all the things I mentioned above, and much more.
As I was walking through some line of codes I stumbled upon this problem a couple of days ago,
- (void)dealloc {
...
[self.postOfficeService deregister:self];
...
}
Where the de-registration from the Post Office Service is an asynchronous operation, even if it's not self evident from the interface as there's no block or function passed to the postOfficeService.
The internal implementation of postOfficeService's -deregister method is something like that
// -deregister:(id)formerSubscriber implementation
//some trivial checks here
// deregister former subscriber
dispatch_asynch(_serialQueue, ^{
[self.subcribers removeObject:formerSubscriber];
});
...
The container, self.subscribers, does perfectly its job and contains only weak references. I.e. it is a NSHashTable.
As long as the deregistration method got called within the dealloc method, I keep on getting a crash while postOfficeService is trying to remove the former subscribers from its list inside that asynch block, which is used for thread safety purposes I guess.
Adding a breakpoint on [self.subscribers removeObject:formerSubscriber], it's possible to notice that the formerSubscriber object is always a NSZombieObject. That's the reason for crashes.
I know that it's possible to get thread safety for deregister method without incurring in this problem - I figure it should be enough use the dispatch_synch in lieu of the dispatch_asynch version
I think this is one of the reason why asynchronous methods shouldn't be called within dealloc methods.
But the question is how's possible to constantly get NSZombie objects even if we are in an ARC environment and the container objects is a NSHashTable (so it should be working I guess)?
The rule is: When dealloc is called, the object will be gone once dealloc returns to its caller (whoever called release when the reference count was 0), and nothing is going to prevent this.
Before ARC, you might have tried to retain an object inside dealloc - doesn't help; once dealloc is called the object will go (and dealloc will be called only once for it, in case you do a retain / release inside dealloc). ARC does the same, just automatically.
Using ARC doesn't means all your memory problem magically disappeared.
What happened is
[obj release] called by ARC
[obj dealloc]
[obj.postOfficeService deregister:obj]
[obj retain] - sorry you can't cancel the deallocation process
dispatch_async
free(obj) - from this point, obj is a zombie
GCD scheduling tasks
dispatch_async execute task
use obj - crash
The correct solution is use dispatch_sync to make sure you not trying to use object after it is deallocated. (be careful about dead lock)
Don't call asynchronous cleanup methods from dealloc. It's just not a good idea. Your -deregister should be synchronous.
NSHashTable stores pointers - it's the equivalent of __unsafe_unretained or assign - UNLESS it was created using +weakObjectsHashTable or the equivalent set of options (NSHashTableZeroingWeakMemory and NSPointerFunctionsObjectPersonality). If it was not created that way, it is quite likely you will have values pointing to zombie objects.
The question of "why am I getting zombies" is best answered by profiling your application with the Zombies template in Instruments and stimulating the required behavior.
I agree with the others that you should probably avoid asynchronous cleanup in your -dealloc method. However, it may be possible to fix this by making the parameter to -deregister: __unsafe_unretained. That method would then have to treat the pointer purely as a opaque value. It must not dereference it or message it. Unfortunately, you don't control the implementation of NSHashTable and can't guarantee that. Even if NSHashTable could be relied upon, the interface of -removeObject: takes an implicitly strong object pointer, so ARC might retain the pointer when it's copied from the unsafe unretained pointer.
You might use the C function API for hash tables (e.g. NSHashRemove()) as suggested in the overview for the NSHashTable class.
Which of the following code section is correct?
Definition of correct for "me":
It should not have a retain cycle and so should not leak.
It must guarantee the running of method2 and method3. So MyObject variable in block must never ever be nil.(which may occur in __weak definitions...) (I do not want to check if it is nil to prevent crash. I always want it to be non-nil)
Update: (Additional Info)
Instruments tool did show strange leaks until I replace __block with __weak. However, after that I remembered that __weak references may disappear anytime. I have to be sure that it doesn't disappear and leak too. I don't have a timer. This someMethod is called on main thread when it observes a specific NSNotification.
#implementation MyObject...
-(void)someMethod{
AnotherObject *abc=[[AnotherObject alloc]init];
__weak MyObject *weakSelf=self;
abc.onSuccess=^{
__strong MyObject * strongSelf = weakSelf;
[strongSelf method2];
[strongSelf method3];
}
}
OR
#implementation MyObject...
-(void)someMethod{
AnotherObject *abc=[[AnotherObject alloc]init];
__block MyObject *blockSelf=self;
abc.onSuccess=^{
[blockSelf method2];
[blockSelf method3];
blockSelf=nil;
}
}
Update 2: Actual Code which always leaks if I don't use __weak:
__block RButton *_self=self;
_aimageView.onSuccess=^(void){
[_self.headerLabel setText:[_self.book title]];
_self = nil;
};
A block can mention self without causing any leak. So the first thing to do is specify the circumstances. Why do you think your block leaks? Have you checked? There's no point worrying if there is no reason to worry.
If the block's mentioning self does cause a leak, then the steps you can take depend upon the reason why that is happening. But you haven't shown us that. For example, a dispatch timer block that mentions self might cause a retain cycle, but when you are done with the timer you can break the cycle, so then there's no leak.
Thus it is better to understand a particular retain cycle than to program every block defensively when you don't have to.
EDIT (in response to your comment) This code from my book demonstrates various ways of handling memory management in an NSNotification observer situation: click here
I have looked at your actual code in "Update 2", but it's missing a lot of information. For example, is _aimageView an instance variable? local variable? or what? And what causes this onSuccess to be called?
If _aimageView is a local variable then I don't see evidence of a retain cycle.
My first thought is I don't understand why you want to guarantee that the code inside the body of the block runs in this example. It looks like the code inside is just updating some UI elements. Well, if the UI is no longer displaying (as when the current object has no references to it other than perhaps by this block), what's the point of updating the UI elements?
It's important to know what causes onSuccess to be called because different types of callbacks require different memory management architectures. For example, if the block is fired in response to a touch or some kind of event like that, then chances are that the object pointed to by self (which is probably some kind of view or view controller) must be still alive in order that the event occurs. If that's the case, then __weak will do what you want.
Basically, by the naming of these variables, it is reasonable to conclude that _aimageView is probably an image view that is conceptually "owned" by the current object, and the onSuccess is a completion block that is "owned" by the image view. Unless some other object has a strong reference to it, the "owned" object's lifetime is limited to its "owning" object's lifetime. Thus the block will not outlive the image view, which will not outlive the current object.
The only way that what you are afraid of (when the block runs, the object pointed to by self is deallocated) can happen, is if some other object stores a strong reference to _aimageView, or to the block. For the block, it's very unlikely that a "success block" of one object will be stored with other objects. For the image view, it's similarly unlikely if the image view "belongs" to the current object. (It's conceivable that it may be stored by the autorelease pool or something; but the autorelease pool will not call stuff on it except release, so that's not a problem.)
The only exception I can think of is if the image view is kept by a pending network operation or something, which when it is done calls the onSucess block. But if that were the case, I would say it's bad design to have a single object serve as both a view and a network operation. Rather, in that case, one should have a dedicated network operation object, which is a local variable, and set a completion block on it (e.g. store image in image view, set labels, etc.), start the operation, and not need to store the operation. Then the block can refer to self strongly, but there is no retain cycle.
To summarize, the block (and the image view that owns it) should fall into one of two categories, based on who keeps it alive (i.e. who retains it, who maintains a strong reference to it):
If self keeps it alive: e.g. A view controller keeps its views and subviews alive. In this case, it is safe to use __weak because the block does not exist outside of the life of self.
If someone else keeps it alive: e.g. an alert view -- you just create it and show it; the system maintains it on screen afterwards. In this case, self should not (and does not need to) have a reference to it, and it's okay to reference self strongly in the block; it won't cause a retain cycle.
Try to avoid situations where both self and someone else keep it alive.
As you require to guarantee that method2 and method3 are executed then you have a requirement that the object referenced by self stays alive. To do this you follow the standard pattern: keep a strong reference for as long as you need it. Your second code fragment does that.
Reference cycles are not inherently bad, it is unmanaged ones that are. Here you make a cycle and then break it, so there is no issue.
(Note as you can send a message to nil the first code fragment will not crash if strongSelf is nil - it just won't do anything.)
-(void)someMethod{
AnotherObject *abc=[[AnotherObject alloc]init];
abc.onSuccess=^{
[self method2];
[self method3];
}
}
This will make. It won't cause a retain cycle.