{"action":"created","issue":{"url":"https://api.github.com/repos/facebook/AsyncDisplayKit/issues/688","labels_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/issues/688/labels{/name}","comments_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/issues/688/comments","events_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/issues/688/events","html_url":"https://github.com/facebook/AsyncDisplayKit/pull/688","id":108558914,"number":688,"title":"Ensure data consistency between ASDataController and its delegate while executing update transactions","user":{"login":"nguyenhuy","id":587874,"avatar_url":"https://avatars.githubusercontent.com/u/587874?v=3","gravatar_id":"","url":"https://api.github.com/users/nguyenhuy","html_url":"https://github.com/nguyenhuy","followers_url":"https://api.github.com/users/nguyenhuy/followers","following_url":"https://api.github.com/users/nguyenhuy/following{/other_user}","gists_url":"https://api.github.com/users/nguyenhuy/gists{/gist_id}","starred_url":"https://api.github.com/users/nguyenhuy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nguyenhuy/subscriptions","organizations_url":"https://api.github.com/users/nguyenhuy/orgs","repos_url":"https://api.github.com/users/nguyenhuy/repos","events_url":"https://api.github.com/users/nguyenhuy/events{/privacy}","received_events_url":"https://api.github.com/users/nguyenhuy/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/facebook/AsyncDisplayKit/labels/CLA%20Signed","name":"CLA Signed","color":"bfe5bf"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":8,"created_at":"2015-09-27T20:29:55Z","updated_at":"2015-09-27T21:05:03Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/facebook/AsyncDisplayKit/pulls/688","html_url":"https://github.com/facebook/AsyncDisplayKit/pull/688","diff_url":"https://github.com/facebook/AsyncDisplayKit/pull/688.diff","patch_url":"https://github.com/facebook/AsyncDisplayKit/pull/688.patch"},"body":"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.\r\n\r\nLet 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.\r\n\r\nI 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.\r\n\r\nI 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:\r\n- It has to catch and queue all delegating blocks, then executes them on main thread. \r\n- It doesn't handle the case when data is accessed externally after some edit commands finished,  but before the (single) beginUpdates/endUpdates run loop is executed. It crashes because _completedNodes was modified and is different from what the table view/collection view expects."},"comment":{"url":"https://api.github.com/repos/facebook/AsyncDisplayKit/issues/comments/143595039","html_url":"https://github.com/facebook/AsyncDisplayKit/pull/688#issuecomment-143595039","issue_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/issues/688","id":143595039,"user":{"login":"nguyenhuy","id":587874,"avatar_url":"https://avatars.githubusercontent.com/u/587874?v=3","gravatar_id":"","url":"https://api.github.com/users/nguyenhuy","html_url":"https://github.com/nguyenhuy","followers_url":"https://api.github.com/users/nguyenhuy/followers","following_url":"https://api.github.com/users/nguyenhuy/following{/other_user}","gists_url":"https://api.github.com/users/nguyenhuy/gists{/gist_id}","starred_url":"https://api.github.com/users/nguyenhuy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nguyenhuy/subscriptions","organizations_url":"https://api.github.com/users/nguyenhuy/orgs","repos_url":"https://api.github.com/users/nguyenhuy/repos","events_url":"https://api.github.com/users/nguyenhuy/events{/privacy}","received_events_url":"https://api.github.com/users/nguyenhuy/received_events","type":"User","site_admin":false},"created_at":"2015-09-27T21:05:03Z","updated_at":"2015-09-27T21:05:03Z","body":"@Adlai-Holler explains the problem clearly [here](https://github.com/facebook/AsyncDisplayKit/issues/684#issuecomment-143495549):\r\n> For example, say you have 1 section with 7 items ABCDEFG. You want to do a batch update with (move 5 to 1), (insert X at 0), so you expect the end result to be XFABCDEG.\r\nIf you tell ASTableView about the changes in that order you'll end up with XAFBCDEG which is wrong. If you tell ASTableView about the changes in reverse order you'll end up with XEABCDFG"}}