Fix mutating array datasource bug

Summary:
Copy objects when retrieving from datasource to account for the edge case where the returned data is a mutable array.

Issue fixed: #999

- [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.
- [x] I have reviewed the [contributing guide](https://github.com/Instagram/IGListKit/blob/master/.github/CONTRIBUTING.md)
Closes https://github.com/Instagram/IGListKit/pull/1109

Differential Revision: D7246645

Pulled By: rnystrom

fbshipit-source-id: d9b0c2ba07983bf46327d4ee1ba0eba2e194ba19
This commit is contained in:
Kashish Goel 2018-03-12 15:18:59 -07:00 committed by Facebook Github Bot
parent 6fa9be5d9f
commit 0f75e851a6
3 changed files with 21 additions and 1 deletions

View file

@ -12,6 +12,7 @@ The changelog for `IGListKit`. Also see the [releases](https://github.com/instag
- 5x improvement to diffing performance when result is only inserts or deletes. [Ryan Nystrom](https://github.com/rnystrom) [(tbd)](tbd)
### Fixes
- Copy objects when retrieving from datasource to prevent modification of models in binding section controller. [Kashish Goel](https://github.com/kashishgoel) [(#1109)](https://github.com/Instagram/IGListKit/pull/1109)
3.2.0
-----

View file

@ -114,7 +114,7 @@ typedef NS_ENUM(NSInteger, IGListDiffingSectionState) {
self.object = object;
if (oldObject == nil) {
self.viewModels = [self.dataSource sectionController:self viewModelsForObject:object];
self.viewModels = [[self.dataSource sectionController:self viewModelsForObject:object] copy];
} else {
IGAssert([oldObject isEqualToDiffableObject:object],
@"Unequal objects %@ and %@ will cause IGListBindingSectionController to reload the entire section",

View file

@ -296,5 +296,24 @@
[self waitForExpectationsWithTimeout:30 handler:nil];
}
- (void)test_whenUpdating_withMutableArrayObject_thatViewModelsDontMutate {
NSArray *objects = @[
@"foo",
@"bar"
];
NSMutableArray *initObjects = [NSMutableArray arrayWithArray:objects];
[self setupWithObjects:@[
[[IGTestDiffingObject alloc] initWithKey:@1 objects:initObjects]
]];
IGTestDiffingSectionController *section = [self.adapter sectionControllerForObject:self.dataSource.objects.firstObject];
NSArray *oldModels = [section.viewModels copy];
[initObjects removeAllObjects];
XCTAssertEqual(oldModels, section.viewModels);
}
@end