【问题标题】:Diffable Data source with more than one section using core data具有多个使用核心数据的部分的 Diffable 数据源
【发布时间】:2020-02-18 23:08:35
【问题描述】:

WWDC 2019 确实包含了 iOS 的新内容以及 TableViewsCollectionView 的新数据源 UITableViewDiffableDataSource

我已经成功地将上述新数据源与核心数据集成,删除和插入新记录没有任何问题,不幸的是,我在将项目从一个部分移动到另一个部分时遇到问题,如果我试图移动该问题就会出现该部分的最后一个单元格。

下面是我的代码:

表格视图设置

private func setupTableView() {
       diffableDataSource = UITableViewDiffableDataSource<Int, Reminder>(tableView: remindersTableView) { (tableView, indexPath, reminder) -> UITableViewCell? in
           let cell = tableView.dequeueReusableCell(withIdentifier: "SYReminderCompactCell", for: indexPath) as! SYReminderCompactCell
        var reminderDateString = ""
        let reminderTitle = "\(reminder.emoji ?? "") \(reminder.title  ?? "")"

        if let date = reminder.date {// check if reminder has date or no , if yes check number of todos and if date in today
            let dateFormatter = SYDateFormatterManager.sharedManager.getDateFormaatter()
            dateFormatter.dateStyle = .none
            dateFormatter.timeStyle = .short
            reminderDateString = dateFormatter.string(from: date)
        }

            let toDosList = SYCoreDataManager.sharedManager.fetchAllToDosToOneReminder(reminder: reminder)
                 cell.indexPath = indexPath
                 cell.showMoreDelegate = self
                 cell.initializeToDosCompactView(toDoList: toDosList ?? [],reminderTitleText: reminderTitle,reminderDateText: reminderDateString)
                 cell.changeTextViewStyle(isChecked: reminder.isCompleted)

           return cell
       }

    setupSnapshot(animated: true)
   }

使用表格视图数据创建NSDiffableDataSourceSnapshot

private func setupSnapshot(animated: Bool) {
    diffableDataSourceSnapshot = NSDiffableDataSourceSnapshot<Int, Reminder>()

    for (i , section) in (fetchedResultsController.sections?.enumerated())! {
        diffableDataSourceSnapshot.appendSections([i])
        let items = section.objects
        diffableDataSourceSnapshot.appendItems(items as! [Reminder])
        diffableDataSource?.apply(self.diffableDataSourceSnapshot, animatingDifferences: animated, completion: nil)
    }

}

NSFetchedResultsControllerDelegate 用于部分和行

     func controller(_ controller: 
    NSFetchedResultsController<NSFetchRequestResult>, didChange 
    anObject: Any, at indexPath: IndexPath?, for type: 
    NSFetchedResultsChangeType, 
   newIndexPath: IndexPath?) {

    switch type {
    case .insert:
        if let indexPath = newIndexPath {
            let section = fetchedResultsController.sections![indexPath.section]
            self.diffableDataSourceSnapshot.appendItems(section.objects as! [Reminder], toSection: indexPath.section)
            self.diffableDataSource?.apply(self.diffableDataSourceSnapshot, animatingDifferences: true)

        }
        break
    case .update:
        break
    case .delete:

        if let indexPath = indexPath {
            guard let item = self.diffableDataSource?.itemIdentifier(for: indexPath) else { return }
            self.diffableDataSourceSnapshot.deleteItems([item])
            self.diffableDataSource?.apply(self.diffableDataSourceSnapshot, animatingDifferences: true)
        }
        break
    case .move:
        if let indexPath = indexPath {
            guard let item = self.diffableDataSource?.itemIdentifier(for: indexPath) else { return }
            self.diffableDataSourceSnapshot.appendSections([indexPath.section])
            self.diffableDataSourceSnapshot.deleteItems([item])
            self.diffableDataSource?.apply(self.diffableDataSourceSnapshot, animatingDifferences: true)
        }
        if let newIndexPath = newIndexPath {
            let section = fetchedResultsController.sections![newIndexPath.section]

            // let items = fetchedResultsController.object(at: indexPath)
            print("snapppp" , diffableDataSourceSnapshot.sectionIdentifiers)
            let items = section.objects as! [Reminder]

            self.diffableDataSourceSnapshot.appendItems(items, toSection: newIndexPath.section)
            self.diffableDataSource?.apply(self.diffableDataSourceSnapshot, animatingDifferences: true)
        }
        break
    }
}

func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, for type: NSFetchedResultsChangeType) {
    switch type {
    case .insert:
        setupSnapshot(animated: false)
        break
    case .update:
        break
    case .delete:
        let section = self.diffableDataSourceSnapshot.sectionIdentifiers[sectionIndex]
        self.diffableDataSourceSnapshot.deleteSections([section])
                self.diffableDataSource?.apply(self.diffableDataSourceSnapshot, animatingDifferences: true)
        //setupSnapshot(animated: false)

        break
    case .move:
        break
    }
}

【问题讨论】:

  • “问题出现” - 什么问题?请更准确地描述发生的情况。你也有这条线diffableDataSource?.apply(self.diffableDataSourceSnapshot, animatingDifferences: animated, completion: nil),它不应该在for循环里面。您确定要在 for 循环中应用快照更改吗?我很确定用户不会注意到它,所以我不确定它是否有意义。我建议将其移出 for 循环。

标签: ios swift ios13 diffabledatasource


【解决方案1】:
  • 要顺利使用 Core Data,数据源必须声明为

    UITableViewDiffableDataSource<String,NSManagedObjectID>
    
  • setupTableView 中重命名闭包参数标签

    (tableView, indexPath, objectID) -> UITableViewCell? in
    

    并获得提醒

    let reminder = self.fetchedResultsController.object(at: indexPath)
    

    let reminder = try! self.managedObjectContext.existingObject(with: objectID) as! Reminder
    
  • 然后替换整个方法

    func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, 
         didChange anObject: Any, 
         at indexPath: IndexPath?, 
         for type: NSFetchedResultsChangeType, 
         newIndexPath: IndexPath?) { ... }
    

    func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, 
         didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, 
         for type: NSFetchedResultsChangeType) { ... }
    

    只用

    func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChangeContentWith snapshot: NSDiffableDataSourceSnapshotReference) {       
        self.diffableDataSource.apply(snapshot as NSDiffableDataSourceSnapshot<String, NSManagedObjectID>, animatingDifferences: true)
    }
    
  • 同时删除方法setupSnapshot,不需要。在调用performFetch 并在托管对象上下文中发生任何更改后,框架会正确创建快照并调用委托方法。

【讨论】:

  • 好答案我只会补充说 animatingDifferences 应该是 true 还是 false 取决于它是否在初始 performFetch 期间。
  • 请问您是否有任何参考来源,讨论为什么在 DiffableDataSource 中应使用 NSManagedObjectID 而不是 NSManagedObject?谢谢。
  • @CheokYanCheng WWDC 2019 相关视频。
  • 谢谢。我能得到的最接近的是developer.apple.com/videos/play/wwdc2019/230(使用核心数据制作应用程序)。但它并没有专门讨论与 NSManagedObjectID 的使用。如果您使用的是 NSManagedObjectID,是不是如果有内容更改,您就无法检测到这种情况?因为,具有不同内容的 2 个对象可以具有相同的 NSManagedObjectID。
  • NSManagedObjectID 只是一种快速识别特定记录的方法。无论如何确定两个快照的差异
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-13
  • 1970-01-01
相关资源
最近更新 更多