Realm Swift使用

时间:2017-01-08 17:23:20

标签: ios uicollectionview realm

我有一个我刚刚添加了部分的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部分。当我编辑项目时,我的应用程序因此而崩溃,因此我搜索了{{3}在GitHub上发布问题。 Pawelkata(评论员)提到,对问题(现已关闭)的快速解决方法是在switch语句的collectionView.reloadData()情况下调用update

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密切相关的stackoverflow问题,其中@jpsim回答了某人关于在tableView中有多个部分的问题。在评论中@MikePollard询问是否可以将tableView与多个部分与领域集合通知相结合。 JPSim说这很棘手,但可能。虽然我有一个collectionView而不是tableView,但我假设这也是可能的。

我尝试了什么:

  1. 由于我需要知道项目来自哪个部分,因此我创建了一个变量来存储所选项目的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.这是我对错误的解释。我的解释是否正确?为什么不删除该项目?

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

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

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

  3. 我错过了什么?

1 个答案:

答案 0 :(得分:2)

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

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