Post

Replies

Boosts

Views

Activity

How to reload a single cell when using UITableViewDiffableDataSource
In my project I am using a UITableView with a UITableViewDiffableDataSource. I love how easy it is to get up and running with very little boiler plate code and all the free animations. It's a great API! In my project I have implemented a trailing swipe action AND a context menu action. The action allows the user to mark the message read or unread similar to the native Mail app in iOS. I had assumed that this could be accomplished using the following code: enum Section: CaseIterable {     case main } struct Item: Hashable {     var isRead: Bool     let identifier = UUID() 		/* Hashable */     static func == (lhs: Item, rhs: Item) -> Bool {         return lhs.identifier == rhs.identifier     }     func hash(into hasher: inout Hasher) {         hasher.combine(identifier)     } } class ViewController: UITableViewController { 		var dataSource: UITableViewDiffableDataSource<Section, Item>! 		... 		func markItemRead(_ item: Item) { 				var snapshot = dataSource.snapshot() 				var updatedItem = item         updatedItem.isRead = true         snapshot.reloadItems(updatedItem)         self.dataSource.apply(snapshot) 		} } I assumed the method reloadItems(_:) was intended to replace using reloadRows(at:with:) since that method is not available to you when you are using UITableViewDiffableDataSource. So far I have run into this error - https://developer.apple.com/forums/thread/651333, usually when I am using a struct for my model object with inferred Hashable conformance OR even sometimes with a class, but I can't see to put my finger on it. Once I am past getting that error, I am noticing that the method doesn't seem to do what I want. The dataSource holds onto the old object with the old value for isRead. So when the cell is reloading it's view, it doesn't change at all, because it receives the old value for the isRead property. That lead me to this workaround: func markItemRead(_ item: Item) {     let oldSnapshot = dataSource.snapshot()     let oldItems = oldSnapshot.itemIdentifiers(inSection: .main)     let updatedItems: [Item] = oldItems.map {         if $0 == item {             var updatedItem = $0             updatedItem.isRead = true             return updatedItem         }         return $0     }     var snapshot = NSDiffableDataSourceSnapshot<Section, ConversationsController.Conversation>()     snapshot.appendSections([.main])     snapshot.appendItems(updatedItems, toSection: .main)     dataSource.apply(snapshot)     DispatchQueue.main.async {         var snapshot = self.dataSource.snapshot()         snapshot.reloadItems([item])         self.dataSource.apply(snapshot)         self.refreshBadge()     } } The DispatchQueue.main.async was a last ditch effort to get it working and it finally did, but this definitely does not feel right. If someone has been able to figure it out. I would appreciate some help in understanding what/how reloadItems(_:) is intended to work. I have a feeling it all comes down to Hashable but I am not sure exactly what. Thanks!
1
0
4k
Jun ’20
Error with Diffable DataSource - reload items
I am repeatedly seeing this error when attempting to call reloadItems(_:) on a NSDiffableDataSourceSnapshot instance.** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid parameter not satisfying: indexPath || ignoreInvalidItems' var dataSource: UITableViewDiffableDataSource<Section, Foo>! func incrementFoo(_ foo: Foo) {     var snapshot = dataSource.snapshot()     var foo = foo     foo.upvoteCount += 1     snapshot.reloadItems([foo])     dataSource.apply(snapshot) }
1
0
1.4k
Jun ’20