自定义dealloc和ARC(Objective-C)

211

我在我的iPad应用程序中有一个“切换语言”功能,它使用观察器。每个视图控制器在其viewDidLoad:期间向我的观察器注册自己。

- (void)viewDidLoad
{
    [super viewDidLoad];
    [observer registerObject:self];
}
当用户点击“更改语言”按钮时,新语言被存储在我的模型中,观察者会被通知并在其注册的对象上调用updateUi:选择器。这个方法非常有效,但是当我有TabBarController中的视图控制器时,就会遇到问题。这是因为当tab条加载时,它从它的子控制器获取tab图标而不初始化视图,所以viewDidLoad:不会被调用,所以这些视图控制器不会接收到语言更改通知。因此,我将我的registerObject:调用移到了init方法中。
以前我使用viewDidLoad:来向观察者注册,我使用viewDidUnload:来取消注册。由于我现在在init中进行注册,因此在dealloc中取消注册非常合理。
但是我遇到的问题是:
- (void) dealloc
{
    [observer unregisterObject:self];
    [super dealloc];
}

我遇到了这个错误:

ARC禁止显式调用'dealloc'的消息发送

由于我需要调用[super dealloc]来确保超类正确地清理,但ARC禁止那样做,现在我被卡住了。有没有另一种方式可以在对象即将销毁时得到通知?


顺便提一下 - 这种情况可能会导致内存泄漏,而在泄漏工具中不会显示。如果dataModel保留了对观察者的引用(即使是ivars,在ARC下也是默认的),dealloc将永远不会被调用,因为保留计数将大于零。因此,您可能需要手动注销观察者以使dealloc首先被调用。 - Błażej Czapp
我为左右手选项实现了类似的功能。唯一需要该消息的VC是当前显示的VC。其他VC在viewDidLoad或viewDidAppear中查看模型以对界面进行更改。也许像这样的东西会更好。 - Doug Watkins
@BlazejCzapp 因为他正在使用 UITabBarController,假设 UITabBarController 将始终保留对已注册控制器的引用(因为我猜测这是其“子”控制器的情况),那么内存泄漏仍然会成为一个问题吗?我不知道何时将分配已注册的控制器。谢谢。 - Objectif
1个回答

424

使用ARC时,您不需要显式地调用[super dealloc] - 编译器会为您处理它(如Clang LLVM ARC文档第7.1.2章所述):

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

4
如果视图持有对观察者的引用,而观察者也持有对该视图的引用,那么就会出现循环引用。因此视图的引用计数大于0,dealloc方法永远不会被调用。在dealloc方法中调用[observer unregisterObject:self]是否有意义?我漏掉了什么? - user443854
这不会起作用。因为观察者本身持有对控制器的引用。这将防止dealloc首先被调用。 - hasan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接