【问题标题】:iOS KVO - Cannot remove an observeriOS KVO - 无法删除观察者
【发布时间】:2015-07-29 18:25:44
【问题描述】:

我有一个简单的符合 KVO 的 Viewcontroller,其中包含以下内容:

  - (void) viewDidAppear:(BOOL)animated
    {
        [super viewDidAppear:animated];



        [self addObserver:self forKeyPath:@"importStuff" options:0 context:NULL];
        [self addObserver:self forKeyPath:@"importStuffFailed" options:0 context:NULL];
        }

    - (void) viewWillDisappear:(BOOL)animated
    {
        [super viewWillDisappear:animated];

        [self removeObserver:self forKeyPath:@"importStuff"];
        [self removeObserver:self forKeyPath:@"importStuffFailed"];
      }

我遇到的问题是有时用户报告以下错误:

Cannot remove an observer <MyViewController 0x145d0c8d0> for the key path "importStuff" from <MyViewController 0x1741b2280> because it is not registered as an observer.

addObserver 调用不会在代码中的其他任何地方调用。是关于我缺少的生命周期的东西吗?不是 viewDidAppear 保证被调用一次(所以它应该注册键吗?)

【问题讨论】:

  • 这不是处理 KVO 的安全方法。如果您的应用被电话打断,则不会调用 viewWillDisappear,但在应用重新启动时可能会再次调用 viewDidAppear。还有许多其他不太理想的可能性。您应该考虑使用更可靠的方法来添加和删除观察者(viewDidLoad、dealloc 等)
  • 感谢您的知识。如果我调用 addObserver 两次会发生什么?那么我是否也必须两次删除观察者?这篇文章还说 ViewDidAppear 只被调用一次:stackoverflow.com/questions/11534396/…
  • 不回答您的问题,但您可以使用@try {[self removeObserver:self forKeyPath:@"yourKeyPath"];} @catch (NSException * __unused exception) {} 保护自己免受错误的影响
  • @vib 不不不不。不。我是否必须解释这真的是非常非常糟糕的做法?这并不能解决任何问题,只会导致您的程序无法按预期工作并在稍后的某个时间崩溃而没有说明原因。不记录异常也是一个非常糟糕的主意。异常表明出现了问题,您应该注意而不是忽略。
  • 不,不能保证 viewDidAppear 每次都会与 viewWillDisappear 匹配。在这些方法中处理 KVO 是非常不好的做法。不要试!在更多记录的配对中执行此操作,例如 viewDidLoad/dealloc

标签: ios key-value-observing


【解决方案1】:

Apple Docs 说有一种方法可以在视图仅可见时添加观察者。根据图 1 - 有效状态转换,您可以使用对 viewWillAppear/viewWillDisppear 来添加和删除观察者。同时你可以使用init/dealloc pair,但不能使用viewDidLoad/dealloc——视图不能加载,但控制器被释放。

你的代码应该是:

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    [self addObserver:self forKeyPath:@"importStuff" options:0 context:NULL];
    [self addObserver:self forKeyPath:@"importStuffFailed" options:0 context:NULL];
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];

    [self removeObserver:self forKeyPath:@"importStuff"];
    [self removeObserver:self forKeyPath:@"importStuffFailed"];
}

【讨论】:

    【解决方案2】:

    不能保证viewDidAppear 每次都会与viewWillDisappear 匹配。这意味着您的 KVO 注册/注销可能是不平衡和不确定的。您应该在viewDidLoaddealloc 等有保证的配对中执行KVO 注册/注销。

    【讨论】:

    • 我有一个疑问,我的案例控制器是某些视图属性的观察者。视图是否可以在控制器的 deinit 方法中使用?
    • @AmberK 视图应该在 deinit 方法中仍然可用。如果不是,它可能会崩溃,所以它应该很容易测试。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多