【问题标题】:Dealloc called without viewDidLoad being called (crash on removing KVO observer)在没有调用 viewDidLoad 的情况下调用了 Dealloc(删除 KVO 观察者时崩溃)
【发布时间】:2015-10-13 22:18:03
【问题描述】:

我正在使用UITabBarController,我的第三个选项卡观察到单例数据存储上的一个数组(在viewDidLoad 中实现)。

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

使用断点,我看到viewDidLoad 从未在此第三个选项卡上调用,但是当我退出时会调用 dealloc。到底是怎么回事?我假设UITabBarController 在我进入情节提要时持有对第三个选项卡的引用,但不会“加载”该选项卡。然而,当我释放标签栏控制器时,iOS 会调用 dealloc。

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

【问题讨论】:

    标签: ios objective-c iphone uitabbarcontroller


    【解决方案1】:

    不要使用@try。 Objective-C 中的异常应该总是considered programmer error,并且应该是致命的。

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


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


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

    【讨论】:

      【解决方案2】:

      viewDidLoad 在视图第一次出现之前被调用。 UITabBarController 正在创建相关的UIViewController,但在创建过程中未加载视图。当用户第一次访问该选项卡时,它会按需加载。

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

      【讨论】:

        【解决方案3】:

        可能找到了更好的解决方案。我在方法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;
        }
        

        【讨论】:

          【解决方案4】:

          使用标志来设置是否已设置 KVO。根据应用的状态,使用 @try 会产生内存管理问题。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-07-07
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多