Prevent/Postpone table在 table 不可见时查看来自 NSFetchedResultsController 的更新

Prevent/Postpone tableview updates from NSFetchedResultsController when table is not visible

Xcode11.0

Swift 5.1

我正在使用 Core Data 开发 "simple" 应用程序。

单个核心数据实体名为主题,包括标题(字符串)、详细信息(字符串)和收藏夹(布尔)

我正在使用带有 3 个选项卡的自定义 UITabBarController - Random TopicFavorite TopicsAll Topics

Favorite Topics 和 All Topics 是共享相同子类的 UITableView,TopicsViewController

使用自定义 TopicTabBarController 我在 TopicsViewController 中设置了一个 属性,基于选项卡,它确定谓词是否与共享此控制器的两个选项卡的 FetchRequest 一起使用。

即使使用 FRC 缓存,这也能按预期工作(我是 Swift 的新手!)

如果某个主题在任何视图中被收藏,收藏主题和所有主题中的 tableView 都会更新以反映该更改。这正是我想要的。

问题是我收到一条警告,说 tableView 在不可见的情况下正在更新:

UITableView was told to layout its visible cells and other contents without being in the view hierarchy (the table view or one of its superviews has not been added to a window).

我在 UITableViewAlertForLayoutOutsideViewHierarchy 处设置了一个符号断点,但目前我有点难以理解它。

如果未加载视图,我尝试从 FRC 委托方法提前返回,但这显然不是解决方案。就像我说的,这对我来说是全新的。

我认为将 FRC Delegate 设置为 nil 并返回到 self as suggested in this post 会有所帮助,但这只会阻止 managedObjectContext 保存(至少这是我在 Navicat 中看到的)。我可以单步执行代码并查看控制器 class 的正确实例正在根据我为谓词设置的自定义 属性 进行操作。

这是该部分的相关代码:

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    self.fetchedResultsController.delegate = self
    self.performFetch()
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    self.fetchedResultsController.delegate = nil
}

// MARK:- Helper methods
func performFetch() {

    do {
        try fetchedResultsController.performFetch()
    } catch {
        fatalCoreDataError(error)
    }
}

这是保存实体的地方,上面的代码不会发生这种情况:

@objc func toggleFavorite(_ sender: UIButton) {
    let buttonPosition = sender.convert(sender.bounds.origin, to: tableView)
    if let indexPath = tableView.indexPathForRow(at: buttonPosition) {
        let topic = fetchedResultsController.object(at: indexPath)
        topic.isFavorite = !topic.isFavorite
        try! managedContext.save()
    }
}

这是 more details 的要点。我发现这样阅读起来容易多了。

我也是刚刚在 Apple Dev 论坛上看到 this post。看起来是同样的问题,未解决。

老实说,我不知道这些信息是太多了还是太少了。真的希望我在尝试解释问题时偶然发现解决方案。

感谢您的宝贵时间。

不管它的价值如何,我收到了同样的警告,我能够通过执行与您尝试的非常相似的操作来修复它。基本上唯一的区别是 tableView.reloadData().

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    fetchedResultsController.delegate = self
    tableView.reloadData()
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    fetchedResultsController.delegate = nil
}

...虽然我认为执行提取会同样有效?