When I use .animation(.spring(), value: favoriteArticles) on a ScrollView to enable animation of delete or add an item. favoriteArticles is data fetched from CoreData.
Then I got this error Instance method 'animation(_:value:)' requires that 'FetchedResults<Article>' conform to 'Equatable', how could I make CoreData object confirm to Equatable protocol.
Section {
ScrollView(.vertical, showsIndicators: false) {
ForEach(favoriteArticles) { article in
favoriteArticleRow(article: article)
}
}
.padding(.horizontal, 16)
.padding(.top, 14)
.confirmationDialog("This favorite will be deleted.", isPresented: $showDeleteOneAlert, titleVisibility: .visible) {
Button("Delete", role: .destructive) {
print("~ delete \(String(describing: selectedFavorite?.text))")
guard let selectedFavorite = selectedFavorite else { return }
delete(article: selectedFavorite)
// If favorites is empty, show control panel, and reset showDeleteButton
if favoriteArticles.isEmpty {
showDeleteButton.toggle()
homeViewState.showControlPanel.toggle()
}
}
}
.animation(.spring(), value: favoriteArticles)
>Solution :
CoreData objects are NSObjects, which do conform to Equatable. It is FetchedResult that doesn’t conform to Equatable.
If you just want to animate the addition and removal of favourite articles, you can use favoriteArticles.count as the value: parameter. This is assuming that in each transaction, there are either only additions or only removals of favourited articles.
If an article can be favourited and another un-favourited within the same transaction, the transaction will not be animated. favoriteArticles.count did not change, after all. To handle this, you would need to load all the fetched results into memory and compare their ids. e.g. favoriteArticles.map(\.objectID). This may be expensive depending on how many favourited articles there are.
Alternatively, if you know when an article is going to be (un)favourited, wrap that with withAnimation.