Custom dealloc and ARC (Objective-C)
Asked Answered
R

1

211

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?

Rad answered 3/9, 2011 at 8:50 Comment(3)
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.Fecteau
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.Kr
@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. ThanksTraitor
C
425

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)
}
Confront answered 3/9, 2011 at 8:59 Comment(2)
If view holds a reference to observer, and observer holds reference to the view, then we have a circular reference. So the view's reference count is greater than 0, and dealloc is never called. Does it make sense to call [observer unregisterObject:self] in dealloc? What am I missing?Swetlana
thats want work. cause the observer itself holds a reference to the controller. that will preventing the dealloc of getting called in the first placeAnnabell

© 2022 - 2024 — McMap. All rights reserved.