Do observers need to be removed in iPhone applications - iphone

I subclass MPMoviePlayerController. In that class I attached all possible notifications that I need. DidFinishPlayback, ExitFullScreen etc. in it's loading method. My question is, if I want to STOP movie and dismiss movie player view can I (and do I need to) remove observers in moviePlayerPlaybackStateDidChange method on stateStopped? What can happen if I don't do that?

The most important place to remove an observer of any kind is in the dealloc method. It is best practice to remove the observers as soon as your done observing but absolutely needs to be done by dealloc.
The reason for this is because if you register as an observer for something and your class gets deallocated the object you were observing could possible try and callback to the now deallocated object. More than likely this will cause an EXC_BAD_ACCESS and close your application.

Related

Why is NSURLConnection and CAAnimation delegate retained?

i am new to ios development. I just came to know that their are two delegates in Foundation that are retained. My understanding says that a delegate must always be loosely coupled. So why these two are specifically retained?
Thanks
Commonly, a delegate is needed for the entire lifetime of an object, which is why it is usually a weak/non-retained reference. Otherwise, neither the object nor the delegate could ever be deallocated, because they would both wait for the other to go away.
In the case of NSURLConnection and CAAnimation however, the delegate is actually only needed for a specific task that has some sort of "finished" state. When the connection finishes loading/is cancelled or the animation has reached its end, they can just release the delegate themselves and thus break the retain cycle.

What's a good place to unregister an observer from the notification center?

When I add an observer to the default notification center, where would I unregister that?
Example: I have a UIView subclass which lives inside a view controller. That subclass is an observer for the FooBarNotification. If this notification is posted, that view will get it. But now, the view controller decides to throw away the view. Is the best place the -dealloc method of the view itself?
Are there any rules like memory management rules? For example: Must I unregister an observer where I registered it? i.e. the view registers itself in it's init method, so it should unregister itself in it's -dealloc method?
(not talking about push notifications, but NSNotificationCenter)
The only rule is to make sure the observer lives longer than the registration period.
Since -addObserver:… will not -retain the observer, if the registration outlives the observer itself, your program will crash.
Apple doesn't specify any rules to unregister the observer. -dealloc is fine. Just use common sense. E.g. if that observer may persist even after the view controller throw it away, then you should unregister at that throw-away procedure, otherwise the observer may receive unwanted notifications.
Certainly it should be done in the dealloc, but basically when you no longer need notifications.
One possible place is to override the willMoveToWindow: message on the UIView and remove the notification when the view is removed from a window:
- (void)willMoveToWindow:(UIWindow *)newWindow
{
if (window == nil) {
// view removed from a window -- remove notifications here
}
[super willMoveToWindow:newWindow];
}
I usually add my observers in viewWillAppear and remove them again in viewWillDisappear.
This works because almost always I won't want a notification to be picked up by a view that isn't currently in the foreground (any longer living observers I register in my coordinator)
Dealloc and viewDidUnload if you have registered for notifications in viewDidLoad.

How to solve this performSelector:withObject:afterDelay: problem?

I have a view controller, which calls performSelector:withObject:afterDelay. However, if I remove that view controller right after calling this, my app crashes as soon as the system tries to perform the delayed selector on that (deleted) view controller.
Now how can I go about this? I need to get rid of the view controller to save memory, so there's no way to let it hang around.
Any way to cancel a delayed perform selector before it performs?
I suggest to use an NSTimer instead. You can simply invalidate the timer to make sure it will never be called after the UIViewController has gone away. A good moment to invalidate the timer is for example in viewWillDisappear:.
This does mean that the timer is owned by the view controller. But that is a good design anyway.
You can't perform a selector on a deleted object, you either need to have the object around, or do the work with some other smaller object that you can have hanging around.
To cancel there is a cancelPreviousPerformRequestsWithTarget:selector:object: or cancelPreviousPerformRequestsWithTarget: method.

iPhone Delegates - How to use them correctly

I have 2 or 3 views in my iPhone application where I have various pieces of functionality that use delegates. In all cases the delegates are assigned to "self", responding specifically to that view's actions and interacting with instance variables.
However, if I do something that takes a bit of time with a delegate, and leave the view, obviously it crashes my app as the delegate methods get called on a view I've left.
Typically in my delegate methods I am doing things like interacting with IBOutlets, calling other instance methods, saving data to Core Data etc...
How can I work with delegates better? Is what I'm doing typical, or not?
Thanks for any guidance!
Depends on the use case. If, for example, you've got a UINavigationController that manages a ViewController that use something such as Location Services, when you pop the View Controller off of the stack you're going to want to set the CLLocationManager's delegate to nil. You can do this in the dealloc method.
Can you give a specific example of an issue you're facing?
I've encountered this situation once when dealing with MapKit (race conditions involving delegate callbacks and delegate deallocation). However, in general, I think it's an indication of a bad design decision when your delegate becomes invalidated as a result of race conditions, but I could be wrong.
Typically, the objects that make use of your delegate should exist within the context of the delegate itself. So, for example, the same class that contains various IBOutlets that you want to manage with delegate callbacks should also be the delegate of those IBOutlets. That way, when the class (i.e., the delegate) is deallocated, the IBOutlets are (hopefully) also deallocated, so they won't be making callbacks to anything.
bpapa's right. More generally, if you have a potentially lengthy delegate callback, either make sure that 1) the delegate is an object that won't be deallocated during the lifecycle of the delegator (e.g., UINavigationController managing UIViewControllers) or 2) the delegator's delegate object is set to nil during the delegate's deallocation.
... That last sentence was a mouthful. :)
Your delegates should be declared as
#property (nonatomic, assign) id <MyDelegateProtocol> delegate;
This ensures a weak reference so that when you dealloc the object which has delegate, it only removes the reference and NOT the corresponding object. using (strong) will cause a crash on dealloc.
When calling your delegate, you can check
if (self.delegate && [self.delegate respondsToSelector:#selector(MyDelegateProtocolCallbackMethodName:)] {
[self.delegate MyDelegateProtocolCallbackMethodName:result];]
}
Generally I use delegates for proxy classes which fetch data from a server or edit screens like changing the title of a task in a todo list or editing a model in a database.
The advantage of a delegate is a very clear use case. If you find that multiple parts of your app need to be aware of when an event happens (triggered on 1 screen but perhaps listened for in another), I suggest using NSNotificationCenter to raise notifications, instead of or perhaps in addition to sending a message to your delegate.

best way to release an object that you lose track of

So I am creating an class that does an animation. There is a timer delay. So I will instantiate this class. Have it do its thing then have a timerFinished type of delegate to continue on.
This question comes from my sheltered garbage collection career.
What is the best way to release this object?
Do I have it release itself when it finishes that task (not even sure that this is possible).
Do I have the object that implements the delegate release it?
Having trouble wrapping my mind around the best way to do this.
FWIW, I've found it rather dangerous to have objects that retain/release themselves, for the simple reason that you may have objects hanging around in the background that you don't know about anymore. Even worse, if they message another object, they may be retaining views or controllers you've long closed.
Also, this pattern doesn't work in the garbage collector on MacOS.
So, I'm currently trying to re-educate myself to keep a global NSArray for each class that may have such objects floating around. That way, during debugging I have a place where I can easily see these objects, and I can cancel them from dealloc by e.g. having a "cancelAllConnectionsWithDelegate: self" method.
You should have your object post a notification when it's finished or send a message to its delegate, and the listening object or delegate can handle cleanup of the object.
Generally, if you are not sure when or where to release your object you can call autorelease on it when initializing. Like this:
NSObject *anObject = [[[NSObject alloc] init] autorelease];
Yes, when you're done with the animation, you can send the animation class instance a [self release] message. Just be sure you're really done with the animation class when you send the message.