简体   繁体   English

NSFetchedResultController未在委托中调用controllerDidChangeContent

[英]NSFetchedResultController not calling controllerDidChangeContent in delegate

There are many very similar looking questions on StackOverflow but I am asking this because almost every existing question is caused by not calling performFetch on the FRC. 在StackOverflow上有很多看起来很相似的问题,但是我问这个是因为几乎每个现有问题都是由于未在FRC上调用performFetch引起的。

In this case we are calling it. 在这种情况下,我们称之为。

fetchedResultsController = NSFetchedResultsController(fetchRequest: StepRecord.fetchRequest(forDate: date),
                                              managedObjectContext: theMainThreadContext,
                                                sectionNameKeyPath: nil,
                                                         cacheName: nil)

fetchedResultsController.delegate = self

do {
    try fetchedResultsController.performFetch()
} catch (let error) {
    print(error)
}

Then in a later function, we have something like this... 然后,在以后的功能中,我们将得到如下内容...

func updateScreen() {
    if fetchedResultsController.fetchedObjects.count == 0 {
        // download data and store into core data
    }

    // update the screen
}

And we have the delegate method... 我们有委托方法...

func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
    updateScreen()
}

The place that is writing into core data is definitely writing into a backgroundThreadContext (this is a pattern we have used several times in the app and it is working elsewhere). 写入核心数据的地方肯定是写入backgroundThreadContext (这是我们在应用程序中使用过几次的模式,它在其他地方也可以使用)。

However, the delegate method is not getting called in this case. 但是,在这种情况下不会调用委托方法。

If we exit the screen and go back in the updateScreen method runs and the FRC DOES have data. 如果我们退出屏幕,然后返回updateScreen方法,则运行并且FRC DOES具有数据。 So the fetch request is correct, the download is putting records in the correct place and saving properly and the update screen method is able to get those items and populate the screen. 因此,提取请求正确无误,下载将记录放置在正确的位置并正确保存,并且更新屏幕方法能够获取这些项目并填充屏幕。

The only problem we are having here is that the delegate method is not being called. 我们这里唯一的问题是未调用委托方法。

Is there something we have missed here? 这里有我们想念的东西吗? Like I said, we have used this same pattern in a few places and it works. 就像我说的那样,我们在一些地方使用了相同的模式,并且有效。 It's just in this case that it isn't working. 只是在这种情况下它不起作用。

Let me know if there is any other code you would like to see and I'll pass it along if I can. 让我知道您是否还想查看其他代码,如果可以的话,我会通过。

What is happening is that you are using a different NSManagedObjectContext for saving the downloaded data. 发生的情况是您正在使用其他NSManagedObjectContext保存下载的数据。 That context uses a background queue as you say. 如您所说,该上下文使用后台队列。 But perhaps that context is not a child of the context of the FRC. 但是,这种情况可能不是FRC的背景。 In that case, you need to merge into the main context listening the notification of the other changing. 在这种情况下,您需要合并到主上下文中,以侦听其他更改的通知。

But the easy way to fix it is using a background context that is a child of the main context. 但是,解决此问题的简单方法是使用作为主要上下文子级的背景上下文。 That is, create a new context of type privateQueue and set its parentContext equal to the current context. 也就是说,创建一个类型为privateQueue的新上下文,并将其parentContext设置为等于当前上下文。

TL:DR - Objects that don't exist, won't listen for NSNotifications. TL:DR-不存在的对象将不会监听NSNotifications。

OK, after some serious debugging we finally found the problem that was causing this and it's a doozy. 好的,经过一些认真的调试,我们终于找到了导致此问题的原因,这很麻烦。

So, the code in my question existed inside a class that was essentially a "worker" for a factory class. 因此,我所质疑的代码存在于一个classclass本质上是工厂类的“工人”。

This worker was used by the factory to create an object and return it to the owner of the factory (the "consumer" if you like). 工厂使用了该工人来创建对象,并将其返回给工厂的所有者(如果需要,可以称为“消费者”)。

Consumer                                - view controller
 - Factory                              - strongly referenced
    - Worker                            - function variable
       - FetchedResultsController stuff - strongly referenced

While we were keeping a strong reference to the Factory, the factory didn't actually store a reference to the worker outside of the function it was used in. 虽然我们一直对Factory保持强烈的引用,但是工厂实际上并没有在其使用的功能之外存储对worker的引用。

This means that by the time the download completed and saved stuff into CoreData, the Fetched Results Controller and the "worker" didn't actually exist in memory anymore. 这意味着,当下载完成并将内容保存到CoreData中时,Fetched Results Controller和“ worker”实际上不再存在于内存中。

So, the easy fix was to add a stored reference to the worker. 因此,简单的解决方法是将存储的引用添加到工作程序。

The longer fix is to refactor some code I think, but that's a job for another day. 较长的修复方法是重构我认为的某些代码,但这是另一天的工作。

Thanks for all the help. 感谢您的所有帮助。 It definitely helped us root out the problem. 它无疑帮助我们消除了问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM