Realm Swift 使用部分更新 collectionView

Posted

技术标签:

【中文标题】Realm Swift 使用部分更新 collectionView【英文标题】:Realm Swift updating collectionView with sections 【发布时间】:2017-01-08 17:23:20 【问题描述】:

我有一个刚刚添加了部分的 collectionView,我正在使用 RealmSwift。在添加这些部分之前,我能够对数据进行更改并在我的 collectionView 中查看它们的更新/删除。

我按照docs 添加了一个通知,以便我的结果对象中的更改会触发 UI 更改;请注意,我对我的 collectionView 进行了适当的更改。

func notificationSubscription(for outfits: Results<Outfit>) -> NotificationToken 
    return outfits.addNotificationBlock( [weak self] (changes: RealmCollectionChange<Results<Outfit>>) in
        self?.updateUI(with: changes)
    )


func updateUI(with changes: RealmCollectionChange<Results<Outfit>>) 
    switch changes 
    case .initial(_):
        collectionView.reloadData()
    case let .update(_, deletions, insertions, modifications):
        collectionView.performBatchUpdates(
            self.collectionView.reloadItems(at: modifications.map  IndexPath(row: $0, section: 0) )
            self.collectionView.insertItems(at: insertions.map  IndexPath(row: $0, section: 0) )
            self.collectionView.deleteItems(at: deletions.map  IndexPath(row: $0, section: 0) )
        , completion:  (completed: Bool) in
            self.collectionView.reloadData()
        )
        break
    case let .error(error):
        print(error.localizedDescription)
    

我很清楚,updateUI(with: changes) 中的问题是 IndexPaths 被硬编码为第 0 节。当我编辑一个项目时,我的应用程序因此崩溃,所以我四处搜索并在 GitHub 上遇到了this 问题. Pawelkata(评论员)提到,该问题(现已关闭)的快速解决方法是在 switch 语句的 update 情况下调用 collectionView.reloadData()

func updateUI(with changes: RealmCollectionChange<Results<Outfit>>) 
    switch changes 
    case .initial(_):
        collectionView.reloadData()
    case let .update(_, deletions, insertions, modifications):
        collectionView.reloadData()
        break
    case let .error(error):
        print(error.localizedDescription)
    

虽然快速修复适用于修改和插入,但在删除的情况下会失败。这是因为新数据是在其他地方添加/修改的,但删除发生在同一个 viewController 上,因此这些更改实际上不会更新 UI。

我发现this 密切相关的 *** 问题,其中@jpsim 回答了某人关于在 tableView 中有多个部分的问题。在 cmets 中,@MikePollard 询问是否可以将带有多个部分的 tableView 与领域集合通知结合起来。 JPSim 说这很棘手,但有可能。虽然我有一个 collectionView 而不是 tableView,但我假设这也是可能的。

我尝试过的:

    因为我需要知道项目来自哪个部分,所以我创建了一个变量来存储所选项目的 indexPath。 var indexPathForDeletion = IndexPath()

    然后我在didSelectItem 中设置,并在updateUI(with: changes) 中使用。

    func updateUI(with changes: RealmCollectionChange<Results<Outfit>>) 
        switch changes 
        case .initial(_):
            collectionView.reloadData()
        case let .update(_, deletions, insertions, modifications):
            collectionView.performBatchUpdates(
                self.collectionView.deleteItems(at: [self.indexPathForDeletion])
            , completion:  (completed: Bool) in
                self.collectionView.reloadData()
            )
            break
        case let .error(error):
            print(error.localizedDescription)
        
    
    

    应用程序因Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of items in section 2. The number of items contained in an existing section after the update (2) must be equal to the number of items contained in that section before the update (2), plus or minus the number of items inserted or deleted from that section (0 inserted, 1 deleted) and plus or minus the number of items moved into or out of that section (0 moved in, 0 moved out).' 而崩溃

    我从 2 个项目开始,我删除了 1 个项目,我应该还剩下 1 个项目,但似乎我还有 2 个项目。这是我对错误的解释。我的解释正确吗?为什么不删除项目?

    我有一个哈希表来存储这些部分,它是结果数组,所以我创建了一个函数来更新哈希表,然后重新加载 collectionView。

    func refreshData() 
        getOutfitsByCategory()
        collectionView.reloadData()
    
    
    func getOutfitsByCategory() 
        for category in categories 
            outfitsByCategory[category] = outfits.filter("category = %@", category)
        
    
    

    这给了我一个“更好”的结果,但似乎有些奇怪。我可以删除它们在索引 0 处的项目 iff,无论部分如何。但是,删除索引 0 处的项目将删除它所在的整个部分。

我错过了什么?

【问题讨论】:

【参考方案1】:

根据您的集合视图有多少个部分,为每个部分的每组结果简单地设置一个单独的通知块可能会更容易。这需要为每个部分(以及随后的通知令牌)维护一个单独的 Results 对象,因此根据您拥有的部分的数量,此解决方案可能会有些复杂。

另一个考虑因素可能是尝试RBQFetchedResultsController。这是在 Realm 中可用更改通知之前构建的控制器(作为 Realm 员工的第三方项目),因此虽然它不像主集合通知系统那样“原生”,但它也可以解释表/集合视图部分。

【讨论】:

感谢@TiM!我只有大约十几个部分。我现在意识到我误解了您的建议,但它引导我找到了我实施的解决方案,即为每个部分设置单独的通知。然后我刚刚更新了我的哈希表并重新加载了 collectionView。 @MaryMartinez 怎么办separate notifications

以上是关于Realm Swift 使用部分更新 collectionView的主要内容,如果未能解决你的问题,请参考以下文章

使用 Realm 和 Swift 的具有多个部分的 UITableView

UITableView 使用 Realm 和 Swift 具有多个按字母顺序排列的部分,多个标签与相同的数据连接

升级 Swift Realm Braking Changes,我可以更改类名或如何解决冲突?

如何将图像放入 Realm 数据库中?

如何在 Realm swift 中过滤为当前日期创建的事件?

使用 Swift 过滤 Realm 对象