NSURLConnectionDelegate object losing delegate value - ios

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.

Related

Why am I crashing when trying to create a weak reference to self while dealloc is happening on another thread?

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.

Is messaging other objects initiated from the same archive really safe?

The documentation of awakeFromNib(), https://developer.apple.com/reference/objectivec/nsobject/1402907-awakefromnib, specifies
Because the order in which objects are instantiated from an archive is
not guaranteed, your initialization methods should not send messages
to other objects in the hierarchy. Messages to other objects can be
sent safely from within an awakeFromNib method.
Is it really the case that messages to other objects can be sent safely from within an awakeFromNib method? Though all the objects within the same archive are initialized when an awakeFromNib method is called, the order of the callings of the awakeFromNib method on objects in an archive is not guaranteed, and the execution of the awakeFromNib method of an object can alter the object's value. How can messaging another object in an awakeFromNib method really be safe if we don't know if the other object has executed the awakeFromNib method? Is the documentation wrong?
The documentation means that it is "safe" to message other objects (from the archive) in the sense that all objects in the archive will have been instantiated before any object's awakeFromNib is called. In other words it is guaranteed that the target object instance that you may want to message exist and their properties have been set as per any archived values or values specified by their initialisers.
I think you are asking "what if my awakeFromNib code alters the objects in some way and since I don't know the order of execution, is it "safe" to message other objects then?".
In this case you need to code so that the order of awakeFromNib invocation doesn't matter. This may mean performing operations in some other function.
This doesn't mean that the documentation is incorrect. Messaging other objects in awakeFromNib is generally "safe" but constraints you have put in place by mutating the object graph or object properties in awakeFromNib may mean that you don't get the desired outcome.
It is your responsibility to ensure that any state that doesn't come from the nib itself is either irrelevant or catered for.

Im confused on how can I manipulate the properties inside an instance when it gets deinitialized?

I have this from either the Apple documentation or the swift book
When an instance gets deinitialized, you still have access to the
properties inside the instance and can manipulate them as needed
before the instance totally goes away.
I'm confused, do they mean when we for example do some mathematical action using the instances property in the deinit() method? or lets say when we print a property of type string that was part of a specific instance, also from the deinit() method?
If so, then is the deinit() method the only way to manipulate a property when it is being deinitialized?
if you have a swift class with a a var you know you have to clean up after because ARC can't free it (e.g. C memory), you can still do that in deinit. The pointers stored in the properties are still valid!
it isn't useful for much more though (ok end observing with the notification center or kvo) BECAUSE there is no guarantee WHEN deist is called. ONLY that it is called before deallocation [whenever that is]
deinit is called right before deallocation (when the retainCount reaches 0), so all your properties are still valid and you can print your string. You don't need to set properties to nil explicitly in deinit as that happens automatically.
This being said, most classes don't even need deinit implemented
Most of the time I used deinit to remove observer that the instance is registered to, post any notifications if needed, and things like that.
As far as I know, the deinit method gets called just before the instance gets deinitialized, to give you a final opportuninty to do whatever you need to do (cleanup, close a file, terminate a network connection, etc).
What the documentation says is that, at the time deinit is called your object has not been deinitialized yet (but will be very soon), so you still can (for the last time) access its properties.

what happens if delegate doesnot exist anymore?

I came around a interesting issue while working on my app. Imagine the scenerio where
There exist one object, Lets call it A.
A, then creates an object(B) of some delegation based class, say NSURLConnection.
A assigned itself as delegate of B, provided A has implemented all the required delegate methods.
A asks B to start its processing. In our example i.e. fetching data from some server.
As soon as B finished fetching data, it will call some specified method of A.
In the last step, suppose while calling the methods of A, B finds that the A object doesnt exist anymore. Then what happens???
I'm not sure but does it cause crash?
If yes, then please suggest me how to avoid the situation.
In my case I assigned the viewcontroller as delegate of some object, say X in viewDidLoad method. There are cases when viewcontroller get destroyed before X calls the delegate methods defined in the viewcontroller.
If assigning X's delegate to nil solves the problem. Then where
should i do that.
In short, which method is called only once while unloading phase of view controller likewise
viewDidLoad in its loading phase.
The best way to achieve this kind of communication between classes (where class A could be deallocated at any time) is listening to NSNotifications.
As you stated , using weak(assign) delegates is dangerous and requires extra thought.
Using strong delegates could as well create a memory bloat (why should we retain a view controller so long after popping it from the view anyway?).
For more on NSNotificationCenter and notifications , you can find a lot of info in the SDK docs.. for specific questions, you know where to ask..
You should not reach a situation where one object holds a reference to another object which may be deallocated somewhere else without the owner object being notified.
Either when deallocating object A notify object B (by making member a nill in object B for example) or modify your design/flow to never allow A to be deallocated before B finishes (e.g. retain A when assigning as a delegate in B if possible)
Checking against a valid delegate object should be sufficient enough.
if (delegate)
[delegate method];

iOS: How to handle a released delegate

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];
}

Resources