209
votes

In my little iPad app I have a "switch language" function that uses an observer. Every view controller registers itself with my observer during its viewDidLoad:.

- (void)viewDidLoad
{
    [super viewDidLoad];
    [observer registerObject:self];
}

When the user hits the "change language" button, the new language is stored in my model and the observer is notified and calls an updateUi: selector on its registered objects.

This works very well, except for when I have view controllers in a TabBarController. This is because when the tab bar loads, it fetches the tab icons from its child controllers without initializing the views, so viewDidLoad: isn't called, so those view controllers don't receive language change notifications. Because of this, I moved my registerObject: calls into the init method.

Back when I used viewDidLoad: to register with my observer, I used viewDidUnload: to unregister. Since I'm now registering in init, it makes a lot of sense to unregister in dealloc.

But here is my problem. When I write:

- (void) dealloc
{
    [observer unregisterObject:self];
    [super dealloc];
}

I get this error:

ARC forbids explicit message send of 'dealloc'

Since I need to call [super dealloc] to ensure superclasses clean up properly, but ARC forbids that, I'm now stuck. Is there another way to get informed when my object is dying?

1
As a side note - situation like this can cause a memory leak, which would not show in the Leaks tool. If the dataModel retains the reference to the observer (which is the default thing under ARC, even for ivars), the dealloc will never get called, as the retain count will be larger than zero. So, you may have to manually unregister the observer to enable the dealloc to be called in the first place.Błażej Czapp
I implemented something similar for right and left handed options. The only VC that needs the message is the currently displayed one. Others look at the model in viewDidLoad or viewDidAppear to make changes to the interface. Maybe something like this would work better.Doug Watkins
@BlazejCzapp since he is using a UITabBarController, and let's say the UITabBarController will always hold a reference to the registered controller (as I guess is the case with its 'child' controllers), will the memory leak still be an issue? I don't see when will the registered controller be allocated. ThanksObjectif

1 Answers

422
votes

When using ARC, you simply do not call [super dealloc] explicitly - the compiler handles it for you (as described in the Clang LLVM ARC document, chapter 7.1.2):

- (void) dealloc
{
    [observer unregisterObject:self];
    // [super dealloc]; //(provided by the compiler)
}