diff --git a/CHANGELOG.md b/CHANGELOG.md index 8be08c42..dee35f57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,10 @@ This release closes the [3.0.0 milestone](https://github.com/Instagram/IGListKit - You can now manually move items (cells) within a section controller, ex: `[self.collectionContext moveInSectionController:self fromIndex:0 toIndex:1]`. [Ryan Nystrom](https://github.com/rnystrom) [(#418)](https://github.com/Instagram/IGListKit/pull/418) +### Fixes + +- Gracefully handle a `nil` section controller returned by an `IGListAdapterDataSource`. [Ryan Nystrom](https://github.com/rnystrom) [(tbd)](https://github.com/Instagram/IGListKit/pull/tbd) + 2.2.0 ----- diff --git a/Source/IGListAdapter.m b/Source/IGListAdapter.m index 989ffae2..c58a8e81 100644 --- a/Source/IGListAdapter.m +++ b/Source/IGListAdapter.m @@ -476,7 +476,9 @@ } #endif - NSMutableArray *> *sectionControllers = [[NSMutableArray alloc] init]; + NSMutableArray *> *sectionControllers = [NSMutableArray new]; + NSMutableArray *validObjects = [NSMutableArray new]; + IGListSectionMap *map = self.sectionMap; // collect items that have changed since the last update @@ -498,8 +500,9 @@ sectionController = [dataSource listAdapter:self sectionControllerForObject:object]; } - IGAssert(sectionController != nil, @"Data source <%@> cannot return a nil section controller.", dataSource); if (sectionController == nil) { + IGLKLog(@"WARNING: Ignoring nil section controller returned by data source %@ for object %@.", + dataSource, object); continue; } @@ -516,12 +519,13 @@ } [sectionControllers addObject:sectionController]; + [validObjects addObject:object]; } // clear the view controller and collection context IGListSectionControllerPopThread(); - [map updateWithObjects:objects sectionControllers:sectionControllers]; + [map updateWithObjects:validObjects sectionControllers:sectionControllers]; // now that the maps have been created and contexts are assigned, we consider the section controller "fully loaded" for (id object in updatedObjects) { diff --git a/Tests/IGListAdapterTests.m b/Tests/IGListAdapterTests.m index fb37aa6a..f0302f20 100644 --- a/Tests/IGListAdapterTests.m +++ b/Tests/IGListAdapterTests.m @@ -1060,4 +1060,12 @@ XCTAssertEqual(CGPointEqualToPoint(point, p), YES); \ [mockDelegate verify]; } +- (void)test_whenDataSourceDoesntHandleObject_thatObjectIsDropped { + // IGListTestAdapterDataSource does not handle NSStrings + self.dataSource.objects = @[@1, @"dog", @2]; + [self.adapter reloadDataWithCompletion:nil]; + NSArray *expected = @[@1, @2]; + XCTAssertEqualObjects(self.adapter.objects, expected); +} + @end diff --git a/Tests/Objects/IGListTestAdapterDataSource.m b/Tests/Objects/IGListTestAdapterDataSource.m index 19048871..e7a92db8 100644 --- a/Tests/Objects/IGListTestAdapterDataSource.m +++ b/Tests/Objects/IGListTestAdapterDataSource.m @@ -20,8 +20,10 @@ } - (IGListSectionController *)listAdapter:(IGListAdapter *)listAdapter sectionControllerForObject:(id)object { - IGListTestSection *list = [[IGListTestSection alloc] init]; - return list; + if ([object isKindOfClass:[NSNumber class]]) { + return [IGListTestSection new]; + } + return nil; } - (nullable UIView *)emptyViewForListAdapter:(IGListAdapter *)listAdapter {