I have a object that serves as a connection layer between my view controller and my webservice. This object takes a delegate and informs that delegate whenever data is returned from the server. I am running into a problem where the delegate gets dealloc'd while an http request is running. When the request returns, my object attempts to call a method on the delegate and the app crashes.
What is the best way to handle this. I have read in several places that you should not retain your delegates because very frequently they are retaining the object too, resulting in a cyclic dependence. So if I can't retain my delegate, how do I check if it has been dealloc'd before I call methods on it?
#property (nonatomic, assign) NSObject<ServerConnectionDelegate>* delegate;
Usually you should use delegate pattern if life-time of the delegate is longer than lifetime of worker object. (sorry not sure about correct term here).
You have several options how to fix that:
As a workaround you can set connection delegate to nil in your object's dealloc method.
If data is required (may be for some later usage) you can use NSNotification to inform delegate for any connection events instead of delegate pattern.
As Jack suggested in his comment you can make your delegate a weak property of connection - that will probably be the best solution if your project is using ARC
You should cancel any running request and set it's delegate to nil in dealloc method.
- (void)dealloc
{
[yourWebServiceRequest cancelRequestAndClearDelegate];
[super dealloc];
}
Related
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 have an NSURLConnectionDelegate object which has its own delegate pointing to some search result handler.
When the connection method gets called, the instance of the NSURLConnectionDelegate that is in the debugger has a zero value for the delegate instead of the value I set it to before the request!
I've verified it's the same object by verifying the address, but it doesn't contain the exact same state as before the request is sent. It's as if the object was serialized/deserialized and the delegate variable state wasn't recorded.
How can I debug this?
Turned out I just had to change the delegate property from weak to strong, though that might create a leak in the general case. The delegate must be getting freed earlier than anticipated, so need to add a longer lived reference elsewhere.
I've been struggling with delegates for a long time. It's a very hard concept for me for some reason. I feel like now I have more knowledge, but I'm still far from being confident.
Please tell me if any of these are incorrect/incomplete and why. Thank you.
Delegates implement protocols (unimplemented method headers)
An object (a delegator) can register a delegate (that implements a protocol). This can be done by declaring a property of type id that implements a protocol:
#property (weak, nonatomic) id <MyProtocol> myDelegate;
The delegator can call certain methods (as specified in MyProtocol protocol) on the delegate
Any class that implements the protocol and has to be Delegator's delegate, can declare itself as such:
MyDelegator* myDelegator = segue.destinationViewController;
myDelegator .delegate = self;
Advantages of using a delegate:
a. Reduces coupling (Delegate and Delegator are no longer dependent on each other) which is an important OO design principle
b. makes Delegator more generic; it can now work with other objects, not just this Delegate
1,2 - yes
3 - can call any method of MyProtocol,
4 - correct.
5 - almost right, a very good explanation can be found here delegate and controllers
Yes. But the protocols can be informal.
Yes.
Yes.
Yes and no. Again, the delegate could implement the methods informally... but then you'd want the delegator to verify if the delegate respondsTo (or implements) a method before calling it.
The delegate doesn't necessarily need to set itself as the delegator's delegate (in fact, it shouldn't). Analogy: A business specialist comes to my company and tells my boss to delegate the administrative paperwork to his secretary. The secretary (the delegate) didn't tell the boss (the delegator) to give it work... a third-party did.
A delegate doesn't have to register itself as the delegate (again, it shouldn't). It needs only be able to do the work. Normally the delegate would know nothing (no pointers to) the delegator. So the delegate wouldn't have MyDelegator* myDelegator = segue.destinationViewController;, no.
A) Yes!
B) Yes. Essentially what "reduce coupling" is;
Adding a C): It also allows you to change the behaviour on-the-fly by simply changing the delegate at runtime.
In an iOS class that will not appear as a view e.g.
#interface MyDataClass : NSObject{}
Is there a method that can be overridden and is consistently called at the end of the classes' execution/lifecycle similar to viewDidUnload or dealloc, that can call methods safely?
Alternatively how would one go about implementing a method that could recognise the completion of the useful lifespan of such a class?
I believe dealloc is the last method that's get called if an NSObject subclass is released from memory.
- (void)dealloc
{
[super dealloc];
}
like
- (void)dealloc
{
[super dealloc];
}
?
If you mean a method that runs at the end of lifetime of the Class as a whole (not an instance), I wonder how is the runtime supposed to know when you are done using a class (you can create new instances at any time)? There is an +initialize method, but technically the class itself is available forever (until the program exits).
If you mean the lifetime of an instance, the method you are looking for is -dealloc.
-dealloc is called whenever an object's internal reference count reaches zero. In non-ARC code, if you override it you must call the superclass' implementation, so that ultimately NSObject's -dealloc is called and that is when the memory is freed.
EDIT: Regarding low memory situations, this is how you register for notifications:
// Somewhere inside the -init method of your class
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(myMethod:)
name:UIApplicationDidReceiveMemoryWarningNotification
object:nil];
Inside dealloc, you MUST do this:
[[NSNotificationCenter defaultCenter] removeObserver:self];
...otherwise, your app may crash.
And of course, you must implement a method with the following signature that will be called on low-memory situations:
- (void) myMethod:(NSNotification*) notification
{
// Do some cleanup here, perhaps.
}
(otherwise, your app will crash)
Let's imagine you want to have a different method, other than dealloc, called on low memory conditions (not when the object is deallocated). Which object would call that method?
viewDidUnload is part of the UI Framework and it is called by it. When the application gets a message about low memory conditions, the framework just redirects the message to all active view controllers.
You can implement the same by creating a method on your custom class, e.g. -(void)onLowMemory and then call it from you application delegate from applicationDidReceiveMemoryWarning method or you can register the class to listen to UIApplicationDidReceiveMemoryWarningNotification.
This stackoverflow link more or less answers my question, but not entirely. I think my question has more to do with architecture or method procurement and procedure as opposed to something that can be answered simply.
I've seen a number of posts related to delegates, and I would like to know the proper way to reference them. Suppose I have an object declared like:
#interface MyViewController : UITableViewController {
id delegate;
}
#property (nonatomic, retain) id delegate;
#end
Through the lifecycle of MyViewController, it will make calls to methods of its delegate in response to interaction with the user.
When it's time to get rid of an instance of MyViewController, does the delegate ivar need to be release'ed in the implementation's dealloc method since it is declared with retain?
Or conversely, should delegate even be retained? Perhaps it should be #property (nonatomic, assign) id delegate? According to Apple's docs:
retain ... You typically use this attribute for scalar types such as NSInteger and CGRect, or (in a reference-counted environment) for objects you don’t own such as delegates.
Normally I'd just go with what the docs say, but I've seen a lot of code that calls retain on a delegate. Is this just "bad code?" I defer to the experts here... What is the proper way to handle this?
You generally want to assign delegates rather than retain them, in order to avoid circular retain counts where object A retains object B and object B retains object A. (You might see this referred to as keeping a "weak reference" to the delegate.) For example, consider the following common pattern:
-(void)someMethod {
self.utilityObject = [[[Bar alloc] init] autorelease];
self.utilityObject.delegate = self;
[self.utilityObject doSomeWork];
}
if the utilityObject and delegate properties are both declared using retain, then self now retains self.utilityObject and self.utilityObject retains self.
See Why are Objective-C delegates usually given the property assign instead of retain? for more on this.
If you assign the delegate rather than retaining it then you don't need to worry about releasing it in dealloc.
It is usually indicative of bad design, since most delegates retain their objects (creating the potential for retain loops and thus leaks.) But there are some cases where an object should retain its delegate. These are usually cases where no reference is available to the object, so the delegate cannot be the one to retain it--but that itself can sometimes indicate bad design.
I've heard a lot of opinions on this as well. I don't know the Right Way, but I can tell you what I've arrived at through my own work.
You want to retain anything that you need to preserve your handle on. That's all ownership is, in a reference-counted environment. It's a declaration that "I'll need this later, don't let it go away on me".
That ALSO means you're responsible for releasing your claim on it. If you don't specifically do that, you're prone to various problems, but especially dealing with delegates which might well retain the object they're a delegate of. If you don't deal with your retention of the delegate, the ownership will be cyclical and the objects will leak. But don't forget to release what you retain, and you'll be okay.