In ARC do we need to send removeObserver: explicitly? - objective-c

Do we have to send removeObserver: explicitly for objects that have been added as observers to an NSNotificationCenter before?
I am bit confused and unable to find the exact answer for this.
Please provide me in detail, about this including why we need to removeObserver explicitly, and why don't compiler put it implicitly in class/application?

Yes, you need to call removeObserver:, if you don't the observed class could call all deallocated instance of the observer.

From 10.11 observers are not required to un-register in their deallocation method.
NSNotificationCenter and NSDistributedNotificationCenter no longer
send notifications to registered observers that may be deallocated. If
the observer is able to be stored as a zeroing-weak reference the
underlying storage stores the observer as a zeroing weak reference.
Alternatively, if the object cannot be stored weakly (because it has a
custom retain/release mechanism that would prevent the runtime from
being able to store the object weakly) the object is stored as a
non-weak zeroing reference. This means that observers are not required
to un-register in their deallocation method.[1]

Removing the observer is always a smart idea.
If you don't remove the observer, messages will still be sent, even if the object was deallocated. It might even be attached to another object, which would definitely lead to serious trouble.

You always need to remove observers for KVO as well as for Notifications.

Related

Do observers need to be removed in Swift 4/Objective-C?

I'm trying to implement KVC/KVO in Swift 4. Much of the documentation I've read up on for KVC/KVO in Objective-C states that the observer needs to be removed when you are done with it. But, after looking at Apple's documentation of the implementation of KVO using Swift 4, they don't explicitly state whether or not the observer needs to be removed in a deinit method. They do not include a deinit method in the example class definition. But, I do not want to make any assumptions since all the Objective-C documentation I've read states that the observer needs to be removed.
https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/AdoptingCocoaDesignPatterns.html#//apple_ref/doc/uid/TP40014216-CH7-ID12
I'm just not sure whether or not the observer needs to be removed through a deinit. Any help or point in the direction of a reference would be great, thanks.
If you are talking about NSKeyValueObservation: No they don't.
From the transcript of the WWDC 2017 Video "What is new in Foundation"
There is no need for a deinit where I throw away or tear down my observation because it's tied to the life cycle of that observation token. And so when the controller goes away, the observation token will go away.
The rules around deregistering observers was relaxed in 10.13, from the Foundation Release Notes (emphasis added):
Relaxed Key-Value Observing Unregistration Requirements
Prior to 10.13, KVO would throw an exception if any observers were still registered after an autonotifying object's -dealloc finished running. Additionally, if all observers were removed, but some were removed from another thread during dealloc, the exception would incorrectly still be thrown. This requirement has been relaxed in 10.13, subject to two conditions:
The object must be using KVO autonotifying, rather than manually calling -will and -didChangeValueForKey: (i.e. it should not return NO from +automaticallyNotifiesObserversForKey:)
The object must not override the (private) accessors for internal KVO state
If all of these are true, any remaining observers after -dealloc returns will be cleaned up by KVO; this is also somewhat more efficient than repeatedly calling -removeObserver methods.
HTH

Where is the official mention about observer retain/release of NSNotificationCenter method?

NSNotificationCenter is known not to retain/release the observers. It makes sense, and I also have experienced related issue.
Anyway today I realized that I really am not sure on this. The official documentation doesn't say anything about ref-counting stuffs.
Though its discussion section says that we have to unregister the observer before it deallocates, but it doesn't mean the center will not retain them. And deallocation timing can become different by the behavior of the center.
Then, I couldn't find anything from the documentation.
But in practice, we already know the add/remove observer method doesn't retain the observer by experience. Unretained reference is very exceptional behavior which may cause serious bug, then I believe that there should be an explicit mention on this.
Where is it?
No, observers are not retained. That's why when you make an object an observer, you must make sure that it stops observing in its dealloc method. Logically, an observed object should know nothing about the observer, shouldn't care about observers, and therefore shouldn't hold a strong reference to observers.

How can I check if object isn't deallocated on Objective-C?

How can I check if object isn't deallocated on Objective-C?
The following standard condition checks only if object is initialized:
NSObject *objectVariable = nil;
...
if (objectVariable) {...}
You can't check after-the-fact whether an object is already deallocated or not, because it is invalid to do anything with an object that is deallocated (once an object is deallocated, any pointer that used to point to it is now an invalid pointer, and dereferencing it is undefined behavior). And since you don't know whether it is deallocated or not, and it may be deallocated, you cannot meaningfully examine it in any way. And a deallocated object may well "look like" a valid object if you try to examine it (it is undefined behavior, so any behavior is possible).
If this is an object of your own class, the obvious thing would be to print something or perform some other indicator action in the class's -dealloc method. That will tell you when it is deallocated.
Even if this is an object that is not of your own class, you may be able to either 1) add -dealloc as a category method, if the class doesn't override -dealloc, or 2) swizzle the -dealloc method, if the class does override it. Then you can print something in your version.
You can also profile it in Instruments; the Allocations instrument can tell you how many objects of a given class have been allocated, and how many are alive. If you suspect that you are losing track of objects or there is a retain cycle, the Leaks instrument may be able to tell you that.
I'm in agreement with the comments, If you're doing memory management right, there should be no need for such a check. Nor am I aware of such a check, if the address gets populated with a new object, the check would pass but could still crash your app.
My suggestions are to:
Read up on manual memory management rules, pay special attention to how blocks affect memory management, alloc/init methods, when to use assign, etc. Memory management rules should become second nature to you. Start with this Apple guide.
Run static analysis on your app and fix any memory errors. Fix all the errors really, these are bugs in your app. (CMD+Shift+B or Product->Analyze in the menu)
Reproduce the crash in Instruments using zombies. Read the retain/release report to find out where the object may have been over-released. (CMD+I or Product->Profile. Select Zombies in the window that appears)
Consider converting to ARC. Converting to ARC doesn't get you completely off the hook for understanding ObjC memory management, but it will take a lot of the burden off of you.

What kind of property should be set to nil in dealloc?

I'm using ARC. Will ARC automatically release all the properties in dealloc? Is it necessary to manual set all public properties and private field to nil? Are there any good pattern to follow?
Under ARC, the pattern is... don't do anything in dealloc, or even implement it. ARC takes care of your properties and instance variables for you.
The only exception is that dealloc is a good place to unregister for notifications, if your object has registered for any.
Good question. When using ARC the compiler will implement a dealloc method for you and will handle implicitly the release of your instance variables and properties.
You may still need a custom -dealloc if your class needs to do anything other than releasing memory (e.g unregister for notifications like jrturton mentioned).
You can get a good grasp of what's you need to consider when transitioning to ARC in those Apple official notes.

iOS: Releasing Object Thats In Use (ARC)

I have an object that I have created that subscribes to some NSNotificationCenter notifications, but it is being released, since I don't have a pointer to the instantiation. The instantiation has a delegate that will call a method back to another class I have, so I felt it unnecessary to also have a pointer to it, since the pointer doesn't serve any purpose.
Basically, I have an instantiation of a class, DelegateListener (name is just for example purposes), which subscribes to some of the default NSNotificationCeneter's notifications. This instantiation isn't assigned to any pointer after the instantiation ends. The instantiation, however, has a property, delegate. I assign a value to that delegate during the instantiation. That delegate implements methods that I want the DelegateListener to call when the notifications that it subscribed to fire.
The problem with this is that the instantiation of DelegateListener that I create gets released, unless if I assign it to a retained pointer. Is there a way to avoid this automatic release of my DelegateListener instantiation within ARC?
You should store the DelegateListener instance in a static variable if you don't have multiple of them.
I felt it unnecessary to also have a pointer to it, since the pointer doesn't serve any purpose.
The pointer does (or at least should) serve a purpose: when you no longer need to listen to the notifications, you should unsubscribe the DelegateListener from receiving them. At the very least, this should happen when your application goes to the background (unless the point of it is to perform background processing), and when your application terminates.
[[NSNotificationCenter defaultCenter] removeObserver:delegateListener];