Weak reference collection view when queueing update

Summary:
Found a "bug" when adding some new unit tests. The queue method holds a strong ref to the collection view, and doesn't release it until that block is executed. The adapter may have already been released, holding onto the collection view is wasteful.

- [x] All tests pass. Demo project builds and runs.
- [x] I added tests, an experiment, or detailed why my change isn't tested.
- [x] I added an entry to the `CHANGELOG.md` for any breaking changes, enhancements, or bug fixes.
Closes https://github.com/Instagram/IGListKit/pull/930

Differential Revision: D5861975

Pulled By: rnystrom

fbshipit-source-id: 986ead725839d39b30daadf92675b397f8794520
This commit is contained in:
Ryan Nystrom 2017-09-19 08:55:50 -07:00 committed by Facebook Github Bot
parent 3f7c7f316a
commit d322c2e5ae
3 changed files with 26 additions and 2 deletions

View file

@ -2,6 +2,14 @@
The changelog for `IGListKit`. Also see the [releases](https://github.com/instagram/IGListKit/releases) on GitHub.
3.2.0 (upcoming release)
-----
### Fixes
- Weakly reference the `UICollectionView` in coalescence so that it can be released if the rest of system is destroyed. [Ryan Nystrom](https://github.com/rnystrom) [(#tbd)](https://github.com/Instagram/IGListKit/pull/tbd)
3.1.1
-----

View file

@ -380,6 +380,12 @@ void convertReloadToDeleteInsert(NSMutableIndexSet *reloads,
}
__weak __typeof__(self) weakSelf = self;
__weak __typeof__(collectionView) weakCollectionView = collectionView;
// dispatch_async to give the main queue time to collect more batch updates so that a minimum amount of work
// (diffing, etc) is done on main. dispatch_async does not garauntee a full runloop turn will pass though.
// see -performUpdateWithCollectionView:fromObjects:toObjects:animated:]objectTransitionBlock:completion: for more
// details on how coalescence is done.
dispatch_async(dispatch_get_main_queue(), ^{
if (weakSelf.state != IGListBatchUpdateStateIdle
|| ![weakSelf hasChanges]) {
@ -387,9 +393,9 @@ void convertReloadToDeleteInsert(NSMutableIndexSet *reloads,
}
if (weakSelf.hasQueuedReloadData) {
[weakSelf performReloadDataWithCollectionView:collectionView];
[weakSelf performReloadDataWithCollectionView:weakCollectionView];
} else {
[weakSelf performBatchUpdatesWithCollectionView:collectionView];
[weakSelf performBatchUpdatesWithCollectionView:weakCollectionView];
}
});
}

View file

@ -1124,6 +1124,9 @@
- (void)test_whenQueuingUpdate_withSectionControllerBatchUpdate_thatSectionControllerNotRetained {
__weak id weakSectionController = nil;
__weak id weakAdapter = nil;
__weak id weakCollectionView = nil;
@autoreleasepool {
IGListAdapter *adapter = [[IGListAdapter alloc] initWithUpdater:[IGListAdapterUpdater new] viewController:nil];
IGTestDelegateDataSource *dataSource = [IGTestDelegateDataSource new];
@ -1146,9 +1149,16 @@
dataSource.objects = @[object, genTestObject(@2, @2)];
[adapter performUpdatesAnimated:YES completion:^(BOOL finished) {}];
weakAdapter = adapter;
weakCollectionView = collectionView;
weakSectionController = section;
XCTAssertNotNil(weakAdapter);
XCTAssertNotNil(weakCollectionView);
XCTAssertNotNil(weakSectionController);
}
XCTAssertNil(weakAdapter);
XCTAssertNil(weakCollectionView);
XCTAssertNil(weakSectionController);
}