【问题标题】:CNContactStoreDidChangeNotification is fired multiple timesCNContactStoreDidChangeNotification 被多次触发
【发布时间】:2016-01-01 22:16:05
【问题描述】:

当应用程序处于后台状态时更改联系人数据库时,我能够观察到CNContactStoreDidChangeNotification。我很确定NSNotificationCenter 中只添加了一名观察员。 问题是NSNotificationCenter 发布了多次(2、3、5 甚至更多次),即使我只添加了一个新联系人。 问题出在哪里?

【问题讨论】:

  • 这方面有什么更新吗?
  • 我也有这个问题。即使在最好的情况下,添加联系人也会生成至少 2 个 CNContactStoreDidChangeNotification 通知。但是,我的通知仅在我返回我的应用程序时才会出现,而不是在后台时出现。其他人也有这个问题。
  • 我在运行 iOS 10 的 iPhone 上遇到了与 applicationDidBecomeActive 类似的问题,仅在横向模式下。请参阅:stackoverflow.com/questions/39622392/… 我在 Apple Bug Reporter 中打开了一个新错误。 Apple 向我询问了更多细节,我向他们发送了我完整的 Xcode 项目……但我没有解决方案。该错误仍然存​​在...
  • 我认为没有问题。如果您查看从较早的kABDatabaseChangedExternallyNotification 触发的通知中的 userInfo 字典,您会看到该通知实际上是从一个或多个ABSenderProcessNames 触发的,例如 Contacts.app 和 AddressBookSourceSync。如果您尝试从手机更新联系人,您将收到来自 AddressBookSourceSync 的通知。

标签: ios swift nsnotificationcenter cncontact cncontactstore


【解决方案1】:

确保您没有多次添加观察者。如果(例如)您在视图控制器中从 -viewDidLoad-viewDidAppear 调用 -addObserver(因为它们可能在应用程序的整个生命周期中被多次调用),或者从任何应用程序委托中的应用程序状态回调(-applicationDidBecomeActive-applicationWillResignActive-applicationDidEnterBackground-applicationWillEnterForeground 等)。

将对-addObserver 的调用包装在一个条件中,以确保它只能被调用一次(设置一个标志),并在其周围放置 NSLog 语句,以便您可以在调试控制台中看到不止一次。在您的代码中搜索您可能忘记的其他对 -addObserver 的调用。

在添加之前调用-removeObserver,以确保(确保传递与添加时相同的名称和对象)。在不存在的观察者上调用-removeObserver 是可以的。 请注意,这更像是一种创可贴而不是修复 - 您的代码应该足够聪明,可以知道您是否已经添加了它 - 但这可能有助于您诊断问题)。

我刚刚编写了一个快速的最小测试程序,在CNContactStoreDidChangeNotification 上添加了一个观察者(一次!),当我添加或更改联系人时,我只收到一次通知。为自己编写一个类似的测试程序,看看是否得到相同的结果。如果您的测试程序正常运行,那么很可能您的应用正在执行您未预料到的事情(并多次调用-addObserver)。

【讨论】:

  • 您是否在大联系人数据上尝试过(比如我正在测试 500 多个联系人)?我仔细检查了观察者只注册了一次(它是单音的,在调试器中你真的可以遵循它)。尽管如此,每次接触变化我都会得到 3 个回声。我的解决方案是在后台处理更改,并在处理前将线程休眠 3 秒,如果有新更新则取消操作。因此,我确保只会处理“回声”中的最新消息。顺便说一句,在较旧的 iOS 中,我将睡眠时间设置为 2 秒,现在在 10.3.3 中,我将其设置为 3 秒(稍后会出现回声)
  • Jeff 的观察非常好,切中要害。这是人们可能犯的最简单的错误,即多次添加观察者。但问题是真实存在的,这不是由于多次调用 addObserver 造成的。尼克的解决方案可能有效,但应避免睡觉。相反,可以使用计时器或 dispatch_after 来实现这一点。
【解决方案2】:

我遇到了同样的问题,它触发的次数在 2 和 3 之间变化。对我有用的解决方案是设置一个信号量变量,在处理程序中设置并在完成后重置信号量。将地址簿处理包装在信号量的 if 语句中以忽略进一步的调用。 在 buildFrendsAndContacts 中 addressBkSemphore 被重置为 false

- (void)addressBkChange:(NSNotification *)note
{   
    if (addressBkSemphore == false)
    {
        addressBkSemphore = TRUE;
        [self buildFrendsAndContacts];
    }
}

希望对你有帮助。

【讨论】:

  • 其他人提出的解决方案,在处理更改之前暂停,似乎它可能会更好,因为这意味着使用最新版本的地址簿(如果两个更改同时发生 - 比如说如果有人在离线时在另一台设备上进行了一些编辑,然后连接到 wifi)
【解决方案3】:

您可以在几秒钟后启动一次性执行计时器或调度并取消它,以防在那几秒钟内有新的联系人更新,从而确保只有最后一次更新触发的计时器或 dispatch_after 才会真正执行(考虑到考虑到所有更新调用都在一秒钟内一个接一个地出现,据我测试)

顺便说一句,只有在使用我的应用更改同一设备上的联系人时,我才能重现该问题。如果我在连接到同一个苹果帐户的另一台设备上更改联系人,则只有一次更新。

【讨论】:

    猜你喜欢
    • 2013-08-13
    • 1970-01-01
    • 1970-01-01
    • 2012-04-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-06
    • 2016-04-04
    相关资源
    最近更新 更多