调用dealloc时没有调用viewDidLoad(删除KVO观察者时崩溃)

时间:2015-10-13 22:18:03

标签: ios objective-c iphone uitabbarcontroller

我正在使用UITabBarController,我的第3个标签在单个数据存储上观察一个数组(在viewDidLoad中实现)。

目前,如果我只是注销(并从App Delegate更改根视图控制器),则在第3个选项卡上调用dealloc时,应用程序将崩溃并显示消息"无法删除观察者关键路径" X"因为它没有注册为观察员。

使用断点,我发现在第3个选项卡上永远不会调用viewDidLoad,但是当我退出时会调用dealloc。到底是怎么回事?我假设当我进入故事板时UITabBarController持有对第3个标签的引用,但是没有"加载"那个标签。然而,当我发布标签栏控制器时,iOS会调用dealloc。

我应该使用布尔来跟踪viewDidLoad执行,还是尝试使用@try语句删除观察者?是否有更好的设计呢?

4 个答案:

答案 0 :(得分:3)

请勿使用@try。 Objective-C中的异常应始终为considered programmer error,并且应该是致命的。

正如您所说,使用-viewDidLoad中的布尔值设置来避免这种情况。

尚未加载视图,因为只有在需要显示视图时才会加载视图。

原始KVO可能是危险和笨重的。虽然不需要回答这个问题,但ReactiveCocoa显着改善了KVO体验。

答案 1 :(得分:2)

在视图首次出现之前调用

viewDidLoadUITabBarController正在创建相关的UIViewController,但视图未在创建期间加载。当用户第一次访问选项卡时,它会按需加载。

KVO删除有问题,我认为您无法避免在@try中使用dealloc。我建议使用KVOController:它相当容易使用,它也可以处理所有边缘情况。

答案 2 :(得分:1)

可能找到了更好的解决方案。我在方法initWithCoder:(NSCoder *)aDecoder中添加了观察者,该方法在加载父UITabController时被调用。我正在使用故事板,这可能是我需要调用覆盖此方法而不是常规init的原因。立即执行此操作,无需BOOL标记或@try,也不会崩溃。

- (instancetype)initWithCoder:(NSCoder *)aDecoder {
    if (self = [super initWithCoder:aDecoder]) {
        [anObject addObserver:self forKeyPath:aKeyPath options:0 context:NULL];
    }
    return self;
}

答案 3 :(得分:0)

使用标志设置是否已设置KVO。使用@try可以根据应用程序的状态创建内存管理问题。