2017-01-08 80 views
0

我有一个collectionView,我刚刚添加了部分,我正在使用RealmSwift。在添加这些部分之前,我可以对数据进行更改,并在我的collectionView中查看它们的更新/删除。领域Swift更新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.我的应用程序崩溃是由于这让我周围中搜索和跨this问题就在GitHub上,当我编辑了一个项目。 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密切相关的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的项目将删除它所在的整个部分。

我在想什么?

回答

1

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

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

+0

谢谢@TiM!我只有十几个部分。我现在意识到,我误解了你的建议,但它引导了我实施的解决方案,即为每个部分设置单独的通知。然后我更新了我的哈希表并重新加载了collectionView。 –

+0

@MaryMartinez如何做'单独的通知' – aelam