{"action":"created","issue":{"url":"https://api.github.com/repos/facebook/AsyncDisplayKit/issues/484","labels_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/issues/484/labels{/name}","comments_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/issues/484/comments","events_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/issues/484/events","html_url":"https://github.com/facebook/AsyncDisplayKit/issues/484","id":88455557,"number":484,"title":"Crash during reloadData","user":{"login":"victoria-chain","id":547246,"avatar_url":"https://avatars.githubusercontent.com/u/547246?v=3","gravatar_id":"","url":"https://api.github.com/users/victoria-chain","html_url":"https://github.com/victoria-chain","followers_url":"https://api.github.com/users/victoria-chain/followers","following_url":"https://api.github.com/users/victoria-chain/following{/other_user}","gists_url":"https://api.github.com/users/victoria-chain/gists{/gist_id}","starred_url":"https://api.github.com/users/victoria-chain/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/victoria-chain/subscriptions","organizations_url":"https://api.github.com/users/victoria-chain/orgs","repos_url":"https://api.github.com/users/victoria-chain/repos","events_url":"https://api.github.com/users/victoria-chain/events{/privacy}","received_events_url":"https://api.github.com/users/victoria-chain/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":4,"created_at":"2015-06-15T15:16:33Z","updated_at":"2015-06-21T05:49:26Z","closed_at":null,"body":"The problem is in updating visible cell nodes after it's deletion. \r\n\r\nDispatched block ```\r\n[self performSelector:@selector(updateVisibleNodeIndexPaths)\r\nwithObject:nil\r\nafterDelay:0\r\ninModes:@[ NSDefaultRunLoopMode ]];```\r\n\r\nis performing right after ```DELETE_NODES(_nodes, indexPaths, animationOption);``` in ```ASDataController::reloadRowsAtIndexPaths```.\r\nActually, there is no possibility to say when ```updateVisibleNodeIndexPaths``` will be dispatched exactly.\r\n\r\nWe have empty ```_nodes``` array at this moment and NSRangeException raises\r\n\r\n```\r\n2015-06-15 15:06:51.448 NFLMobile[49145:813629] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[NSArray objectsAtIndexes:]: index 4 in index set beyond bounds for empty array'\r\n*** First throw call stack:\r\n(\r\n    0   CoreFoundation                      0x0000000104693c65 __exceptionPreprocess + 165\r\n    1   libobjc.A.dylib                     0x00000001082a0bb7 objc_exception_throw + 45\r\n    2   CoreFoundation                      0x00000001045dd413 -[NSArray objectsAtIndexes:] + 979\r\n    3   NFLMobile                           0x0000000102e2dde5 __ASFindElementsInMultidimensionalArrayAtIndexPaths_block_invoke + 55\r\n    4   NFLMobile                           0x0000000102e2d893 _ZL52ASRecursivelyUpdateMultidimensionalArrayAtIndexPathsP14NSMutableArrayPK7NSArrayRmP11NSIndexPathmU13block_pointerFvS0_P10NSIndexSetmE + 656\r\n    5   NFLMobile                           0x0000000102e2d729 _ZL52ASRecursivelyUpdateMultidimensionalArrayAtIndexPathsP14NSMutableArrayPK7NSArrayRmP11NSIndexPathmU13block_pointerFvS0_P10NSIndexSetmE + 294\r\n    6   NFLMobile                           0x0000000102e2dcfc ASFindElementsInMultidimensionalArrayAtIndexPaths + 322\r\n    7   NFLMobile                           0x0000000102e171f0 -[ASDataController nodesAtIndexPaths:] + 69\r\n    8   NFLMobile                           0x0000000102e370ef -[ASTableView rangeController:nodesAtIndexPaths:] + 31\r\n    9   NFLMobile                           0x0000000102e338b9 -[ASRangeController updateVisibleNodeIndexPaths] + 1161\r\n    10  Foundation                          0x0000000107d011e5 __NSFireDelayedPerform + 387\r\n    11  CoreFoundation                      0x00000001045fb174 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 20\r\n    12  CoreFoundation                      0x00000001045fad35 __CFRunLoopDoTimer + 1045\r\n    13  CoreFoundation                      0x00000001045bcd3d __CFRunLoopRun + 1901\r\n    14  CoreFoundation                      0x00000001045bc366 CFRunLoopRunSpecific + 470\r\n    15  GraphicsServices                    0x000000010a773a3e GSEventRunModal + 161\r\n    16  UIKit                               0x000000010590a900 UIApplicationMain + 1282\r\n    17  NFLMobile                           0x0000000102acbccf main + 127\r\n    18  libdyld.dylib                       0x0000000109724145 start + 1\r\n    19  ???                                 0x0000000000000001 0x0 + 1\r\n)\r\n```\r\nI've found a way to fix this issue by adding a check on array count in callback. It's just a stub, may be the problem should have a different solution.\r\n\r\n```objective-c\r\nNSArray *ASFindElementsInMultidimensionalArrayAtIndexPaths(NSMutableArray *mutableArray, NSArray *indexPaths) {\r\n  NSUInteger curIdx = 0;\r\n  NSIndexPath *indexPath = [[NSIndexPath alloc] init];\r\n  NSMutableArray *deletedElements = [[NSMutableArray alloc] initWithCapacity:indexPaths.count];\r\n\r\n  if (!indexPaths.count) {\r\n    return deletedElements;\r\n  }\r\n\r\n  ASRecursivelyUpdateMultidimensionalArrayAtIndexPaths(mutableArray, indexPaths, curIdx, indexPath, [indexPaths[0] length], ^(NSMutableArray *arr, NSIndexSet *indexSet, NSUInteger idx) {\r\n      if (arr.count > 0) // <<< check count\r\n      {\r\n          [deletedElements addObjectsFromArray:[arr objectsAtIndexes:indexSet]];\r\n      }\r\n  });\r\n\r\n  ASDisplayNodeCAssert(curIdx == indexPaths.count, @\"Indexpath is out of range !\");\r\n\r\n  return deletedElements;\r\n}\r\n```"},"comment":{"url":"https://api.github.com/repos/facebook/AsyncDisplayKit/issues/comments/113865636","html_url":"https://github.com/facebook/AsyncDisplayKit/issues/484#issuecomment-113865636","issue_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/issues/484","id":113865636,"user":{"login":"appleguy","id":565251,"avatar_url":"https://avatars.githubusercontent.com/u/565251?v=3","gravatar_id":"","url":"https://api.github.com/users/appleguy","html_url":"https://github.com/appleguy","followers_url":"https://api.github.com/users/appleguy/followers","following_url":"https://api.github.com/users/appleguy/following{/other_user}","gists_url":"https://api.github.com/users/appleguy/gists{/gist_id}","starred_url":"https://api.github.com/users/appleguy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/appleguy/subscriptions","organizations_url":"https://api.github.com/users/appleguy/orgs","repos_url":"https://api.github.com/users/appleguy/repos","events_url":"https://api.github.com/users/appleguy/events{/privacy}","received_events_url":"https://api.github.com/users/appleguy/received_events","type":"User","site_admin":false},"created_at":"2015-06-21T05:49:26Z","updated_at":"2015-06-21T05:49:26Z","body":"OK, quick look at this suggests that performDataFetchingWithBlock (which locks the data source) is releasing the lock earlier than the original author expected — in effect, the dispatch_async that includes the DELETE_NODES macro escapes the influence of the lock in a way that isn't visually clear.\r\n\r\nThe coalescing behavior is important for performance, but it does appear to be causing a thread race here.  I will investigate tomorrow and develop a fix that uses either queue-based serialization or more careful locking."}}