WWDC 2019
was really packed with new stuff for iOS and the new data sources for TableViews
and CollectionView
which is UITableViewDiffableDataSource
.
I have successfully integrate the above new data source with Core data , delete and insert new record working without any issue , unfortunately I have an issue with move items from section to another , the issue appears if I'm trying to move the last cell in the section .
Below is my code :
Table View Setup
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)
}
Create a NSDiffableDataSourceSnapshot
with the table view data
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
for sections and rows
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
}
}
To work smoothly with Core Data the data source must be declared as
UITableViewDiffableDataSource<String,NSManagedObjectID>
In setupTableView
rename the closure parameter labels with
(tableView, indexPath, objectID) -> UITableViewCell? in
and get the reminder with
let reminder = self.fetchedResultsController.object(at: indexPath)
or
let reminder = try! self.managedObjectContext.existingObject(with: objectID) as! Reminder
Then replace the entire methods
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>,
didChange anObject: Any,
at indexPath: IndexPath?,
for type: NSFetchedResultsChangeType,
newIndexPath: IndexPath?) { ... }
and
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>,
didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int,
for type: NSFetchedResultsChangeType) { ... }
just with
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChangeContentWith snapshot: NSDiffableDataSourceSnapshotReference) {
self.diffableDataSource.apply(snapshot as NSDiffableDataSourceSnapshot<String, NSManagedObjectID>, animatingDifferences: true)
}
Delete also the method setupSnapshot
, it is not needed. After calling performFetch
and on any change in the managed object context the framework creates the snapshot properly and calls the delegate method.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With