-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Ensure data consistency between ASDataController and its delegate while executing update transactions #688
Ensure data consistency between ASDataController and its delegate while executing update transactions #688
Conversation
…le executing update transactions.
P/S: Will add some automated tests once existing tests can be run on Travis reliably (i.e XCode 7 and asyncdisplaykit_node madness). |
Thanks @nguyenhuy !! Just FYI, I believe the build server is working; we can't use Xcode 7 on Travis, but the tests should still be running with 6.4. |
But I naively updated my XCode to 7. Now tests fails locally :( |
:(. I just downloaded 6.4 from Apple's website, which makes the DMG available. Inconvenient, but after spending well over an hour failing to understand the build issue, I can't think of an alternative in the near term about the test issue on Xcode 7... |
Yeah, I will try to look at that issue tomorrow. Will fall back to 6.4 if I have to. Thanks for the info. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move the ASDisplayNodeAssertMainThread() to this method.
I'm wondering if the existing accessor -completedNodes makes sense. I know it is API exposed on ASDataController, I think used by ASRangeController. Right now the names between these don't quite sit right with me, particularly because the external one is mutable, and also is not /actually/ externally exposed at all (at least the method name).
Could we just delete one of these methods, and rename externalCompletedNodes to completedNodes? Not sure if having the header show NSArray as the return type will work seamlessly if the implementation actually returns NSMutableArray.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, the main thing is -nodesAtIndexPaths:
needs a mutable array (here). Maybe casting it is fine?
Not sure if having the header show NSArray as the return type will work seamlessly if the implementation actually returns NSMutableArray.
I either get a NSArray (and still need to cast), or a "duplicate declaration of method completedNodes" error :(
Does this address the order of applying edits, mentioned in #684? |
I don't think it does :( |
@Adlai-Holler explains the problem clearly here:
|
@appleguy Pushed a new commit that removes externalCompletedNodes getter. Let me know what you think about the cast here. Also, do you think I should remove main thread asserts in methods that call completedNodes getter and assume the assert is done in that getter? Does the runtime overhead justifies the assumption? |
@nguyenhuy So the order of edits still matters here? You still expect this diff to cause a crash when the edits are not specifically ordered? When I tested this diff in my app I still got crashes, this log snippet should give you an idea of what is going on. I purposefully disabled any kind of sorting of the updates (as you can probably see) and just applied them in the natural order they were returned from the FRC.
EDIT: Oh and the crash occurred at line 93 of ASMultidimensionalArrayUtils. If you want more info or want me to try some other stuff just let me know. |
@smyrgl well yeah, as mentioned in #684, I think wrong edit order is another separate problem and will be fixed later on. To test this PR, you have to make sorted edit batch and query nodes while the batch is being executed (calling nodeForRowAtIndexPath for example). But thanks for confirming that sorting is still needed and provide the log. It will be very useful for the other fix, and even more so if you post a sample project that crashes :) |
OK, this is a lot better, thanks @nguyenhuy! In it goes :). Later I may rename the new instance variable, although I haven't thought of a better name yet. It seems like it should reflect the fact that it is temporary / transient while committing a transaction of batch edits. It is not very important at all because it is entirely internal to the implementation. I'm not sure who is going to attempt a fix to the ordering issue, but we should likely introduce that "transaction" concept for the batches. |
…nsactions Ensure data consistency between ASDataController and its delegate while executing update transactions
Thanks, @appleguy. I'm not very proud of the name either, but it was the best I could come up with (other alternatives were backingStoreNodes and delegateStateNodes). So feel free to change it. May "shadowWhileBatchingNodes" sound better? Man, I @Adlai-Holler said he can take the ordering issue. |
@nguyenhuy I would be glad to slice off a sample project with one of my core view controllers (can't post the whole project itself for obvious reasons) but it should be plenty for you to test with. I will try to get this done tonight and I'll post a link in here. |
@smyrgl That would be awesome. Please do! |
@nguyenhuy Just catching up after being off for a couple days. This looks like an elegant solution to this tricky issue. I agree that moving all batched updates into a single run loop is the best answer but it represents a significant refactor that is intimidating to say the least. Thanks so much for figuring this out! |
@eanagel my pleasure. Please test it and report any problems found :) |
My attempt to fix #619. The idea is to capture ASDataController's _completedNodes and use that cache for any external queries until a current update transaction finishes.
Let me know what you think on this diff. If we don't want to cater ASDataController to work with UITableView and UICollectionView specific behaviours, I can simply make a wrapper/subclass that sits between UITableView/UICollectionView and ASDataController. It can intercept transaction calls as well as external data queries, and ensures data consistency using the same technique here.
I tested this diff by abusing Kitten sample with a bunch of insertions, deletions and device rotations. Really appreciate if @eanagel, @ryanfitz, @Adlai-Holler and @smyrgl can help me to test as well.
I have another diff that tries to fix the issue by calling beginUpdates, edit command blocks and endUpdates in a single run loop. That diff is more complex and doesn't cover all the edge cases: