-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Core Data] adapter.performUpdates does not trigger any diffing on NSManagedObjects #460
Comments
In my opinion this code is now working as I would expect:
If I take a instance of a object and I edit it, both a and b will contain the change, so the object will always been seen as equal, even if it changed between 2 interactions of the datasource in the collection view. |
@racer1988 You're right about the equality check being correct. Core Data uses mutable models when things change in the background, unfortunately. That makes it a little difficult when using IGListKit. B/c the pointers are the same, its impossible to see that the object has "changed" b/c there's no previous state to go off of. Since My immediate recommendation is to use a different type of immutable model for your lists. You can construct these in the Two ways to update your section controllers when an
Core Data mutability is super tricky (and personally I think its a bad design) so going w/ an immutable model strategy might be better in the long run. |
@racer1988 worth putting out there, if you come up w/ a solid architecture/design for this, it'd be an amazing repo/tutorial/blog post or something. This is definitely a common issue and will only become more common. |
@rnystrom -- CoreData is beautiful, but misunderstood. 😉 There should only ever be one instance of any managed object in CoreData, so you'll need to use some kind of proxy objects to make this work with ListKit. @racer1988 -- Maybe something like this will work. You could generate token objects to hand over to ListKit: final class ManagedObjectToken {
let objectId: NSManagedObjectID
let hasChanges: Bool
init(objectId: NSManagedObjectID, hasChanges: Bool) {
self.objectId = objectId
self.hasChanges = hasChanges
}
}
// also need to implement Equatable for ManagedObjectToken
extension NSManagedObject {
func token() -> ManagedObjectToken {
return ManagedObjectToken(objectId: self.objectID, hasChanges: self.hasChanges)
}
} Your ListKit objects will be I can think of 2 options to deal with this:
I'm not 100% sure if what I have above will work, but something similar should. |
@rnystrom @jessesquires thank you for your answers, now the whole thing and what is supposed to happen makes perfect sense. I added a bit of code examples in #461. I will implement this in my work project, not sure if with ViewModel approach or by passing around NSManagedObjectID (which is also a good idea for a architecture that supports well CoreData multithreading @jessesquires ;). Sometimes it is easy to forget not to pass a coredata object around, and end up with changing thread in the subsequent classes) I will probably write a repository with examples and "tutorial" for IGListKit later on. |
@racer1988
You bet! That's where I was leading 😄 It would be really really helpful. If you're feeling good should we close this? @jessesquires's idea sounds awesome. Let us know if this works out! Might be a worthy example project too?
😅 |
@racer1988 are we ok to close this issue? |
Hi @rnystrom, yea it is ok, sorry I was away |
Hello @rnystrom, @jessesquires I implemented the ViewModel etc.. and I got more issues than before, so We worked on your code here https://github.com/racer1988/IGListKitPerformUpdates Investigation: We thought is due to the objects not been copied, so we implemented NSCopying protocol in the model, but the copy method is never called by IGListKit. We checked IGListKit code and we noticed that perform updates is not making a shallow copy to compare the objects, it is taking the map and the objects from the datasource and using those to make all the comparisons. Instead, Making a shallow copy of the map triggers the NSCopying protocol method on all the child objects, and makes the collection view update correctly the cells that have been edited. I opened a PR for the same reason, can you please let me know if what we are doing makes sense, and if not, how would you fix the example project to achieve the update of the UI. We might have not understood how IGListKit expects to be used to achieve updates. We will try next to use the "copy" fix to see if we can custom implement NSCopying on our CoreData Objects to see if we can use that method to replace old objects with new objects |
@racer1988 what if in |
@rnystrom Yea, good idea, didn't think about moving it out of the framework lol :D However even this approach has a issue. (even in the PR) So going back to the coreData case: This triggers a NSFetchedResultControllerDelegate per object, If i have let's say 100 objects, I get the collectionView object to potentially flicker 100 times. The objects are new, so IGListKit updates the collectionView by doing delete and insert on all of them. My issue remains (or it become a user experience issue?), I probably did not understood the framework: (I am going to try Notification and SectionController refresh next) |
We'll try to implement a better diffing on our side to see if that solves the issue with ViewModel. |
I manage to make the update work on the example project, by implementing a specific diffIdentifier and isEqual method for the model and adding the copying mechanism on the datasource. I guess that it would be nice to add in the IGListKit documentation that the framework is working out of the box only for immutable datamodels that are recalculated every time there is a perform updates. Else if the model is mutable or it is not recalculated, it is necessary to implement NSCopying a create a copy of it in the datasource, in order to get the updates in UI. This is not clear imho in the getting started guide and could bring to misleading development |
Thanks @racer1988 ! We can update the "Getting Started" guide to discuss mutability. It sounds like having a new, dedicated guide for CoreData would be good too. "Working with Core Data". https://github.com/Instagram/IGListKit/tree/master/Guides cc @rnystrom |
Yep, I'll draft something next week, so I can open a PR and we can contribute to it |
Closing as resolved via #515 |
Summary: Issue answered: #407 #460 #461 I did not run any tool to generate documentation - [x] All tests pass. Demo project builds and runs. - [x] I added tests, an experiment, or detailed why my change isn't tested. - [x] I added an entry to the `CHANGELOG.md` for any breaking changes, enhancements, or bug fixes. - [x] I have reviewed the [contributing guide](https://github.com/Instagram/IGListKit/blob/master/.github/CONTRIBUTING.md) Closes #515 Differential Revision: D4621212 Pulled By: jessesquires fbshipit-source-id: 110e3d37d08e7c763b6a6cde70bc83280f7a2bb3
Hello,
I have a question about the framework, because from the doc I would expect a behaviour, but it does not happen.
I cannot provide a example project, because my app is huge and uses CoreData etc.. and it would take me a lot of time to set it up.
The idea is the following:
What happens is:
however:
I would expect that calling performUpdates:
I could call reloadData but I would lose the animation, and the purpose of using the framework.
There is something I understood wrong, or that I am not doing?
You can reproduce this in @rnystrom sample for RayWendlich:
https://koenig-media.raywenderlich.com/uploads/2016/12/MarsLink_Final.zip
I put the code here:
https://github.com/racer1988/IGListKitPerformUpdates
EDIT:
Using a
IGListReloadDataUpdater
instead of aIGListAdapterUpdater
provides the expected result, without animation and losing the scroll position (due to reload data)I hence believe there is a bug (?) in the IGListAdapterUpdater that do not take in account model changes but just inserts and delete. Is this the expected behaviour?
Do I need to write my own adapter to manage the changes to the datamodel?
The text was updated successfully, but these errors were encountered: