diff --git a/CHANGELOG.md b/CHANGELOG.md index cd0d0050..829cd880 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ The changelog for `IGListKit`. Also see the [releases](https://github.com/instag 3.1.0 (**upcoming release**) ----- +### Fixes + +- Prevent a crash when update queued immediately after item batch update. [Ryan Nystrom](https://github.com/rnystrom) (tbd) + 3.0.0 ----- diff --git a/Source/IGListAdapterUpdater.m b/Source/IGListAdapterUpdater.m index 5ed51e0a..75229b8b 100644 --- a/Source/IGListAdapterUpdater.m +++ b/Source/IGListAdapterUpdater.m @@ -94,6 +94,10 @@ } static NSArray *objectsWithDuplicateIdentifiersRemoved(NSArray> *objects) { + if (objects == nil) { + return nil; + } + NSMutableSet *identifiers = [NSMutableSet new]; NSMutableArray *uniqueObjects = [NSMutableArray new]; for (id object in objects) { diff --git a/Tests/IGListAdapterE2ETests.m b/Tests/IGListAdapterE2ETests.m index 70a192b3..9dcf810c 100644 --- a/Tests/IGListAdapterE2ETests.m +++ b/Tests/IGListAdapterE2ETests.m @@ -1480,4 +1480,45 @@ [self waitForExpectationsWithTimeout:30 handler:nil]; } +- (void)test_whenUpdateQueuedDuringBatch_thatUpdateCompletesWithoutCrashing { + [self setupWithObjects:@[ + genTestObject(@1, @4), + genTestObject(@2, @4), + genTestObject(@3, @4), + genTestObject(@4, @4), + ]]; + + IGTestObject *object = self.dataSource.objects[0]; + IGTestDelegateController *sectionController = [self.adapter sectionControllerForObject:object]; + + XCTestExpectation *expect1 = genExpectation; + XCTestExpectation *expect2 = genExpectation; + + [sectionController.collectionContext performBatchAnimated:YES updates:^(id batchContext) { + object.value = @3; + [batchContext deleteInSectionController:sectionController atIndexes:[NSIndexSet indexSetWithIndex:0]]; + + self.dataSource.objects = @[ + genTestObject(@2, @4), + genTestObject(@4, @4), + genTestObject(@1, @3), + ]; + [self.adapter performUpdatesAnimated:YES completion:^(BOOL finished) { + XCTAssertEqual([self.collectionView numberOfSections], 3); + XCTAssertEqual([self.collectionView numberOfItemsInSection:0], 4); + XCTAssertEqual([self.collectionView numberOfItemsInSection:1], 4); + XCTAssertEqual([self.collectionView numberOfItemsInSection:2], 3); + [expect1 fulfill]; + }]; + } completion:^(BOOL finished2) { + XCTAssertEqual([self.collectionView numberOfSections], 4); + XCTAssertEqual([self.collectionView numberOfItemsInSection:0], 3); + XCTAssertEqual([self.collectionView numberOfItemsInSection:1], 4); + XCTAssertEqual([self.collectionView numberOfItemsInSection:2], 4); + XCTAssertEqual([self.collectionView numberOfItemsInSection:3], 4); + [expect2 fulfill]; + }]; + [self waitForExpectationsWithTimeout:30 handler:nil]; +} + @end