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

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.

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.

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.

Why I should access the instance variable directly from within an initialization method?

The Apple Programming with Objective-C document states that:
You should always access the instance variables directly from within
an initialization method because at the time a property is set, the
rest of the object may not yet be completely initialized. Even if you
don’t provide custom accessor methods or know of any side effects from
within your own class, a future subclass may very well override the
behavior.
But I don't know what side effects will be in a setter method, please give me a example to explain why I have to access the instance variable directly from within an initialization method
The answer is simple - it is code smell. Dot notation like self.foobar = something in Objective-C is just a syntactic sugar for messaging.
Sending messages to self is normally fine. But there are two cases you need to avoid them:
1. When the object is being created, and
2. When the object is being destroyed.
At these two times, the object is in a strange in-between state. It lacks integrity. Calling methods during these times is a code smell because every method should maintain invariants as it operates on the object.
If a setter method is overridden by a subclass, you have no guarantee that your instance variable will contain the correct data. If you want to maintain data integrity within your objects during a crucial phase such as initialization, you should do as Apple recommends.
In addition to #JacobRelkin point, side effects can include Key-Value Observing. Other objects can observe changes even during -init* and -dealloc. I've had a KVO -dealloc bug in the past.
It truly is a best practice to setup and tear down the ivars directly.

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

Why only one delegate?

I've read that an object can only have one delegate at once.
But is that really true?
Let's say I make an object with a protocol and from that object I want to gather a lot of data from several other objects. I add every object that conforms to my protocol to an array. Then I just loop through it and call my methods on every delegate.
NSMutableArray *collectFromDelegates = [NSMutableArray alloc]init];
//in delegateArray I keep pointers to every delegate.
for(id delegate in delegateArray){
[collectFromDelegates addObject:[delegate someProtocolMethod]];
}
Is this wrong?
That's not really delegation.
Delegation is a simple and powerful pattern in which one object in a program acts on behalf of, or in coordination with, another object. The delegating object keeps a reference to the other object—the delegate—and at the appropriate time sends a message to it. The message informs the delegate of an event that the delegating object is about to handle or has just handled.
It doesn't make much sense to have more than one object handle an event for you, since it has already been handled. The only reason I could see to have multiple delegates is that if the first fails to handle an event, it can be passed to the next, continuing until some object handles it.
In your example, the objects are acting as data sources. This makes more sense than multiple delegates, but could easily be implemented by having a single data source combine data from multiple objects, which means the object asking for the data doesn't have to worry about how to combine it.
The other case where you would often want multiple objects is receiving notifications of an event. This is not delegation because the objects are not working for the object, just acting on something that happened to the object. This is better implemented using notifications or observing.
Apple's convention is to only have one "delegate" object. But you can set up your own class to have an array of delegates if that's what you need. You might want to call them something else for clarity.
In your example, calling them "dataSources" might be more appropriate.
A class only really needs one delegate, if you have more than one you are solving a different problem. The delegate pattern is used to modify the behaviour of a class. Say for instance we have a Dog class which can bark, but different types of dogs bark in different way. A delegate would be one way of changing the barking behaviour.
If you need more than one you are probably more interested in OBSERVING what your class is doing, it needs to NOTIFY others of current EVENTS. As several other classes might be interested in the behaviour of one you would need an array. In iOS SDK this is already done for you with notifications. This is called the Observer pattern.
Different use cases...
I've read that an object can only have one delegate at once. But it's that really true?
Where did you read that? No, it's not true. For instance, UITableView has two delegates, one to supply the data, the other to handle actions.
A delegate is just an abstract concept - you can have as many delegates as you want. However, this is rarely required and often a poor pattern.
Apple make good use of a source and delegate pattern. Source ivars (a form of delegate) provide data, while delegate ivars are invoked for logical responses. Perhaps this is a better solution?
Alternatively you can use NSNotification to inform many listeners of a single event.
Hope this helps!
Generally, when you want to message multiple classes that are interested in what you class does, you would use NSNotifications. That will however not allow them to return data unless you allow them to send a message to the object of the notification. I'm not sure if that would be a cleaner solution though.
One approach beside the mentioned Notifications could be, that your delegate implementation holds an array of objects conforming to the protocol and calls the protocols method on this as a wrapper.

Resources