{"action":"created","comment":{"url":"https://api.github.com/repos/facebook/AsyncDisplayKit/pulls/comments/42332909","id":42332909,"diff_hunk":"@@ -0,0 +1,217 @@\n+/* Copyright (c) 2015-present, Facebook, Inc.\n+ * All rights reserved.\n+ *\n+ * This source code is licensed under the BSD-style license found in the\n+ * LICENSE file in the root directory of this source tree. An additional grant\n+ * of patent rights can be found in the PATENTS file in the same directory.\n+ */\n+\n+#import \"ASCollectionDataController.h\"\n+\n+#import \"ASAssert.h\"\n+#import \"ASMultidimensionalArrayUtils.h\"\n+#import \"ASDisplayNode.h\"\n+#import \"ASDisplayNodeInternal.h\"\n+#import \"ASDataController+Subclasses.h\"\n+\n+//#define LOG(...) NSLog(__VA_ARGS__)\n+#define LOG(...)\n+\n+@interface ASCollectionDataController ()\n+\n+- (id<ASCollectionDataControllerSource>)collectionDataSource;\n+\n+@end\n+\n+@implementation ASCollectionDataController {\n+  NSMutableDictionary *_pendingNodes;\n+  NSMutableDictionary *_pendingIndexPaths;\n+}\n+\n+- (void)prepareForReloadData\n+{\n+  _pendingNodes = [NSMutableDictionary dictionary];\n+  _pendingIndexPaths = [NSMutableDictionary dictionary];\n+\n+  [[self supplementaryKinds] enumerateObjectsUsingBlock:^(NSString *kind, NSUInteger idx, BOOL *stop) {\n+    LOG(@\"Populating elements of kind: %@\", kind);\n+    NSMutableArray *indexPaths = [NSMutableArray array];","path":"AsyncDisplayKit/Details/ASCollectionDataController.mm","position":38,"original_position":38,"commit_id":"8b7ac3c37dc44e6477680fd445edb4cadfc7dd95","original_commit_id":"8b7ac3c37dc44e6477680fd445edb4cadfc7dd95","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},"body":"Please make make the dictionaries and arrays created in this file use a capacity-aware initializer, e.g. arrayWithCapacity, wherever possible.","created_at":"2015-10-19T02:42:52Z","updated_at":"2015-10-19T02:42:52Z","html_url":"https://github.com/facebook/AsyncDisplayKit/pull/694#discussion_r42332909","pull_request_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/pulls/694","_links":{"self":{"href":"https://api.github.com/repos/facebook/AsyncDisplayKit/pulls/comments/42332909"},"html":{"href":"https://github.com/facebook/AsyncDisplayKit/pull/694#discussion_r42332909"},"pull_request":{"href":"https://api.github.com/repos/facebook/AsyncDisplayKit/pulls/694"}}},"pull_request":{"url":"https://api.github.com/repos/facebook/AsyncDisplayKit/pulls/694","id":46351997,"html_url":"https://github.com/facebook/AsyncDisplayKit/pull/694","diff_url":"https://github.com/facebook/AsyncDisplayKit/pull/694.diff","patch_url":"https://github.com/facebook/AsyncDisplayKit/pull/694.patch","issue_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/issues/694","number":694,"state":"open","locked":false,"title":"Add support for supplementary views in ASCollectionView","user":{"login":"levi","id":8493,"avatar_url":"https://avatars.githubusercontent.com/u/8493?v=3","gravatar_id":"","url":"https://api.github.com/users/levi","html_url":"https://github.com/levi","followers_url":"https://api.github.com/users/levi/followers","following_url":"https://api.github.com/users/levi/following{/other_user}","gists_url":"https://api.github.com/users/levi/gists{/gist_id}","starred_url":"https://api.github.com/users/levi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/levi/subscriptions","organizations_url":"https://api.github.com/users/levi/orgs","repos_url":"https://api.github.com/users/levi/repos","events_url":"https://api.github.com/users/levi/events{/privacy}","received_events_url":"https://api.github.com/users/levi/received_events","type":"User","site_admin":false},"body":":+1: Ready for landing :+1:\r\n\r\nThis patch is a bit of a big one, but something I've needed for my own usage for some time now. What I'm introducing is an extensible addition to `ASCollectionView` and `ASDataController` that supports supplementary views in any `UICollectionViewLayout` (with a bit of custom implementation) and out-of-the-box support for node-backed supplementary views in `UICollectionViewFlowLayouts`.\r\n\r\nThe core concept of this patch's \"extensibility\" is the introduction of the `layoutDelegate` property on `ASCollectionView` that receives `ASCollectionViewLayoutInspecting` conforming objects. An implementation of this protocol provides insight into the behavior of a collection view layout such that the data controller can query the existence of supplementary views and their index paths, something that is control entirely by the collection view's layout.\r\n\r\n`ASDataController` has been updated to allow subclasses to hook into editing events. Its internal `completedNodes` and `editingNodes` stores have been exposed as key-value structures, allowing subclasses to register non-item/row nodes managed by the data controller. `ASCollectionDataController` is the only subclass of the data controller for now, but shows how supplementary nodes of different kinds (node types) are registered in the completed and editing backing stores and manipulated through event hooks. The benefit here is the potential of extending the data controller to support collection view and table view behaviors independently (section header/footer nodes in ASTableView, perhaps?).\r\n\r\nMoreover, I have moved sizing-specific delegate methods from `ASCollectionViewDelegate` to `ASCollectionViewDelegateFlowLayout`, bridging the ASDK API closer to the `UICollectionViewDelegateFlowLayout` original and making `ASCollectionView` more layout-independent. Anyone relying on `collectionView:layout:insetForSectionAtIndex:` will need to update their delegate to conform to this protocol.\r\n\r\n-- Original body --\r\n\r\nMight be best to read through #691 before skimming through this code, as I briefly outlined the direction I'm embarking on in that issue.\r\n\r\nTODO:\r\n- [x] Finish up abstracting some of the internal insert/update/delete behavior in `ASDataController` to be exposed in such a way that a subclass like `ASCollectionDataController` can insert its supplementary view measure/layout passes.\r\n- [x] Get this running in a sample project and battle test the various issues that arise\r\n- [x] Handle section insertion/update/deletion and item insertion/update/deletion from collection view\r\n- [x] Write tests for flow layout inspector implementation\r\n- [x] Implement initial data loading `ASCollectionDataController` hook\r\n- [x] Update collection modifications to support main thread layout passes\r\n- [x] Test stored element kinds in `ASCollectionView`\r\n- [x] Audit public method naming for consistency\r\n\r\nWould love feedback on this. I don't have much time during the week, but have been making this a priority nights/weekends so we can have this ready for 2.0 in November.\r\n\r\nFixes: #669, #588, #737","created_at":"2015-09-30T01:19:42Z","updated_at":"2015-10-19T02:42:52Z","closed_at":null,"merged_at":null,"merge_commit_sha":"f02d9512a4248f0af14f860ecaf907926e628921","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/pulls/694/commits","review_comments_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/pulls/694/comments","review_comment_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/pulls/comments{/number}","comments_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/issues/694/comments","statuses_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/statuses/8b7ac3c37dc44e6477680fd445edb4cadfc7dd95","head":{"label":"levi:supplementary-views","ref":"supplementary-views","sha":"8b7ac3c37dc44e6477680fd445edb4cadfc7dd95","user":{"login":"levi","id":8493,"avatar_url":"https://avatars.githubusercontent.com/u/8493?v=3","gravatar_id":"","url":"https://api.github.com/users/levi","html_url":"https://github.com/levi","followers_url":"https://api.github.com/users/levi/followers","following_url":"https://api.github.com/users/levi/following{/other_user}","gists_url":"https://api.github.com/users/levi/gists{/gist_id}","starred_url":"https://api.github.com/users/levi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/levi/subscriptions","organizations_url":"https://api.github.com/users/levi/orgs","repos_url":"https://api.github.com/users/levi/repos","events_url":"https://api.github.com/users/levi/events{/privacy}","received_events_url":"https://api.github.com/users/levi/received_events","type":"User","site_admin":false},"repo":{"id":35245356,"name":"AsyncDisplayKit","full_name":"levi/AsyncDisplayKit","owner":{"login":"levi","id":8493,"avatar_url":"https://avatars.githubusercontent.com/u/8493?v=3","gravatar_id":"","url":"https://api.github.com/users/levi","html_url":"https://github.com/levi","followers_url":"https://api.github.com/users/levi/followers","following_url":"https://api.github.com/users/levi/following{/other_user}","gists_url":"https://api.github.com/users/levi/gists{/gist_id}","starred_url":"https://api.github.com/users/levi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/levi/subscriptions","organizations_url":"https://api.github.com/users/levi/orgs","repos_url":"https://api.github.com/users/levi/repos","events_url":"https://api.github.com/users/levi/events{/privacy}","received_events_url":"https://api.github.com/users/levi/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/levi/AsyncDisplayKit","description":"Smooth asynchronous user interfaces for iOS apps.","fork":true,"url":"https://api.github.com/repos/levi/AsyncDisplayKit","forks_url":"https://api.github.com/repos/levi/AsyncDisplayKit/forks","keys_url":"https://api.github.com/repos/levi/AsyncDisplayKit/keys{/key_id}","collaborators_url":"https://api.github.com/repos/levi/AsyncDisplayKit/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/levi/AsyncDisplayKit/teams","hooks_url":"https://api.github.com/repos/levi/AsyncDisplayKit/hooks","issue_events_url":"https://api.github.com/repos/levi/AsyncDisplayKit/issues/events{/number}","events_url":"https://api.github.com/repos/levi/AsyncDisplayKit/events","assignees_url":"https://api.github.com/repos/levi/AsyncDisplayKit/assignees{/user}","branches_url":"https://api.github.com/repos/levi/AsyncDisplayKit/branches{/branch}","tags_url":"https://api.github.com/repos/levi/AsyncDisplayKit/tags","blobs_url":"https://api.github.com/repos/levi/AsyncDisplayKit/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/levi/AsyncDisplayKit/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/levi/AsyncDisplayKit/git/refs{/sha}","trees_url":"https://api.github.com/repos/levi/AsyncDisplayKit/git/trees{/sha}","statuses_url":"https://api.github.com/repos/levi/AsyncDisplayKit/statuses/{sha}","languages_url":"https://api.github.com/repos/levi/AsyncDisplayKit/languages","stargazers_url":"https://api.github.com/repos/levi/AsyncDisplayKit/stargazers","contributors_url":"https://api.github.com/repos/levi/AsyncDisplayKit/contributors","subscribers_url":"https://api.github.com/repos/levi/AsyncDisplayKit/subscribers","subscription_url":"https://api.github.com/repos/levi/AsyncDisplayKit/subscription","commits_url":"https://api.github.com/repos/levi/AsyncDisplayKit/commits{/sha}","git_commits_url":"https://api.github.com/repos/levi/AsyncDisplayKit/git/commits{/sha}","comments_url":"https://api.github.com/repos/levi/AsyncDisplayKit/comments{/number}","issue_comment_url":"https://api.github.com/repos/levi/AsyncDisplayKit/issues/comments{/number}","contents_url":"https://api.github.com/repos/levi/AsyncDisplayKit/contents/{+path}","compare_url":"https://api.github.com/repos/levi/AsyncDisplayKit/compare/{base}...{head}","merges_url":"https://api.github.com/repos/levi/AsyncDisplayKit/merges","archive_url":"https://api.github.com/repos/levi/AsyncDisplayKit/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/levi/AsyncDisplayKit/downloads","issues_url":"https://api.github.com/repos/levi/AsyncDisplayKit/issues{/number}","pulls_url":"https://api.github.com/repos/levi/AsyncDisplayKit/pulls{/number}","milestones_url":"https://api.github.com/repos/levi/AsyncDisplayKit/milestones{/number}","notifications_url":"https://api.github.com/repos/levi/AsyncDisplayKit/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/levi/AsyncDisplayKit/labels{/name}","releases_url":"https://api.github.com/repos/levi/AsyncDisplayKit/releases{/id}","created_at":"2015-05-07T21:50:39Z","updated_at":"2015-05-08T04:58:49Z","pushed_at":"2015-10-15T18:41:05Z","git_url":"git://github.com/levi/AsyncDisplayKit.git","ssh_url":"git@github.com:levi/AsyncDisplayKit.git","clone_url":"https://github.com/levi/AsyncDisplayKit.git","svn_url":"https://github.com/levi/AsyncDisplayKit","homepage":"http://asyncdisplaykit.org","size":4410,"stargazers_count":0,"watchers_count":0,"language":"Objective-C","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"supplementary-views"}},"base":{"label":"facebook:master","ref":"master","sha":"57badd9e8924ecb4289928d39a52d28705ebdfa7","user":{"login":"facebook","id":69631,"avatar_url":"https://avatars.githubusercontent.com/u/69631?v=3","gravatar_id":"","url":"https://api.github.com/users/facebook","html_url":"https://github.com/facebook","followers_url":"https://api.github.com/users/facebook/followers","following_url":"https://api.github.com/users/facebook/following{/other_user}","gists_url":"https://api.github.com/users/facebook/gists{/gist_id}","starred_url":"https://api.github.com/users/facebook/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/facebook/subscriptions","organizations_url":"https://api.github.com/users/facebook/orgs","repos_url":"https://api.github.com/users/facebook/repos","events_url":"https://api.github.com/users/facebook/events{/privacy}","received_events_url":"https://api.github.com/users/facebook/received_events","type":"Organization","site_admin":false},"repo":{"id":21265042,"name":"AsyncDisplayKit","full_name":"facebook/AsyncDisplayKit","owner":{"login":"facebook","id":69631,"avatar_url":"https://avatars.githubusercontent.com/u/69631?v=3","gravatar_id":"","url":"https://api.github.com/users/facebook","html_url":"https://github.com/facebook","followers_url":"https://api.github.com/users/facebook/followers","following_url":"https://api.github.com/users/facebook/following{/other_user}","gists_url":"https://api.github.com/users/facebook/gists{/gist_id}","starred_url":"https://api.github.com/users/facebook/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/facebook/subscriptions","organizations_url":"https://api.github.com/users/facebook/orgs","repos_url":"https://api.github.com/users/facebook/repos","events_url":"https://api.github.com/users/facebook/events{/privacy}","received_events_url":"https://api.github.com/users/facebook/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/facebook/AsyncDisplayKit","description":"Smooth asynchronous user interfaces for iOS apps.","fork":false,"url":"https://api.github.com/repos/facebook/AsyncDisplayKit","forks_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/forks","keys_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/keys{/key_id}","collaborators_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/teams","hooks_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/hooks","issue_events_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/issues/events{/number}","events_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/events","assignees_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/assignees{/user}","branches_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/branches{/branch}","tags_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/tags","blobs_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/git/refs{/sha}","trees_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/git/trees{/sha}","statuses_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/statuses/{sha}","languages_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/languages","stargazers_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/stargazers","contributors_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/contributors","subscribers_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/subscribers","subscription_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/subscription","commits_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/commits{/sha}","git_commits_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/git/commits{/sha}","comments_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/comments{/number}","issue_comment_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/issues/comments{/number}","contents_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/contents/{+path}","compare_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/compare/{base}...{head}","merges_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/merges","archive_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/downloads","issues_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/issues{/number}","pulls_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/pulls{/number}","milestones_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/milestones{/number}","notifications_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/labels{/name}","releases_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/releases{/id}","created_at":"2014-06-27T05:29:02Z","updated_at":"2015-10-18T14:52:18Z","pushed_at":"2015-10-15T18:41:07Z","git_url":"git://github.com/facebook/AsyncDisplayKit.git","ssh_url":"git@github.com:facebook/AsyncDisplayKit.git","clone_url":"https://github.com/facebook/AsyncDisplayKit.git","svn_url":"https://github.com/facebook/AsyncDisplayKit","homepage":"http://asyncdisplaykit.org","size":7740,"stargazers_count":5892,"watchers_count":5892,"language":"Objective-C","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":800,"mirror_url":null,"open_issues_count":108,"forks":800,"open_issues":108,"watchers":5892,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/facebook/AsyncDisplayKit/pulls/694"},"html":{"href":"https://github.com/facebook/AsyncDisplayKit/pull/694"},"issue":{"href":"https://api.github.com/repos/facebook/AsyncDisplayKit/issues/694"},"comments":{"href":"https://api.github.com/repos/facebook/AsyncDisplayKit/issues/694/comments"},"review_comments":{"href":"https://api.github.com/repos/facebook/AsyncDisplayKit/pulls/694/comments"},"review_comment":{"href":"https://api.github.com/repos/facebook/AsyncDisplayKit/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/facebook/AsyncDisplayKit/pulls/694/commits"},"statuses":{"href":"https://api.github.com/repos/facebook/AsyncDisplayKit/statuses/8b7ac3c37dc44e6477680fd445edb4cadfc7dd95"}}}}