chainable datasource
TRANSCRIPT
![Page 1: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/1.jpg)
Chainable Data Sources
or how I stopped worrying and started abusing table view updates
Amadour Griffais
CocoaHeads Paris – 8 September 2016
![Page 2: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/2.jpg)
@ * [ : ] ;
Disclaimer
🍓
![Page 3: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/3.jpg)
UITableView *tableView;
![Page 4: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/4.jpg)
- (UITableViewCell*) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"fruit-cell" forIndexPath:indexPath]; Fruit* fruit = self.fruits[0]; cell.titleLabel.text = fruit.name; return cell; }
😎
![Page 5: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/5.jpg)
Animations 😍[tableView beginUpdates]; [self.fruits removeObjectAtIndex:indexPath.row]; [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; [tableView endUpdates];
![Page 6: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/6.jpg)
//Controller - (UITableViewCell*) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"fruit-cell" forIndexPath:indexPath]; Fruit* fruit = self.fruits[0]; //Model cell.titleLabel.text = fruit.name; //View return cell; }
🤓
![Page 7: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/7.jpg)
- (UITableViewCell*) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { FruitCell* cell = (FruitCell*)[tableView dequeueReusableCellWithIdentifier:@"fruit-cell" forIndexPath:indexPath]; cell.fruit = fruit; return cell; }
🤔
![Page 8: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/8.jpg)
- (UITableViewCell*) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { if (indexPath.section == FRUIT_SECTION) { UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"fruit-cell" forIndexPath:indexPath]; Fruit* fruit = self.fruits[0]; cell.titleLabel.text = fruit.name; return cell; } else if (indexPath.section == VEGETABLE_SECTION) { UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"veg-cell" forIndexPath:indexPath]; ...
😒
![Page 9: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/9.jpg)
- (UITableViewCell*) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { switch (indexPath.section) { case FRUIT_SECTION: { UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"fruit-cell" forIndexPath:indexPath]; Fruit* fruit = self.fruits[0]; cell.titleLabel.text = fruit.name; return cell; } break; case VEGETABLE_SECTION: { ...
😟
![Page 10: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/10.jpg)
- (UITableViewCell*) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { if (indexPath.section == AD_SECTION && indexPath.row == AD_ROW) { return [tableView dequeueReusableCellWithIdentifier:@"ad-cell" forIndexPath:indexPath]; } indexPath = [self offsetIndexPath:indexPath ifAfter:AD_INDEX_PATH]; switch (indexPath.section) { case FRUIT_SECTION: { UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"fruit-cell" forIndexPath:indexPath]; ...
😨
![Page 11: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/11.jpg)
- (UITableViewCell*) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { if (indexPath.section == AD_SECTION && indexPath.row == AD_ROW && self.isAdLoaded) { return [tableView dequeueReusableCellWithIdentifier:@"ad-cell" forIndexPath:indexPath]; } indexPath = [self offsetIndexPath:indexPath ifAfter:AD_INDEX_PATH]; switch (indexPath.section) { case FRUIT_SECTION: { UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"fruit-cell" forIndexPath:indexPath]; ...
😰
![Page 12: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/12.jpg)
Animations 😱2016-09-06 14:07:23.167 MyBeautifulTableView[89346:883532] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (1) must be equal to the number of rows contained in that section before the update (9), plus or minus the number of rows inserted or deleted from that section (0 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).' *** First throw call stack: ( 0 CoreFoundation 0x000000010eba034b __exceptionPreprocess + 171 1 libobjc.A.dylib 0x000000010e60121e objc_exception_throw + 48 2 CoreFoundation 0x000000010eba4442 +[NSException raise:format:arguments:] + 98 3 Foundation 0x0000000109620edd -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 195 4 UIKit 0x000000010c2172f4 -[UITableView _endCellAnimationsWithContext:] + 17558 ...
![Page 13: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/13.jpg)
[tableView reloadData];
😢
![Page 14: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/14.jpg)
![Page 15: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/15.jpg)
UITableViewDataSource
![Page 16: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/16.jpg)
UITableViewDataSource
🍓 🍆
💵
♻M
CV
![Page 17: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/17.jpg)
UITableViewDataSource
💩
🍓 🍆
💵
♻M
CV
![Page 18: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/18.jpg)
MCV
🍓
🍆
+
💵
<
🍓
🍓
🍆
🍓
💵
🍆
![Page 19: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/19.jpg)
🍓
🍆
+
💵
<
ChainableDataSource
![Page 20: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/20.jpg)
@protocol ChainableDataSource <NSObject>
- (NSInteger) numberOfSectionsInDataSource; - (NSInteger) numberOfObjectsInDataSourceSection:(NSInteger)section; - (id) dataSourceObjectAtIndexPath:(NSIndexPath*)indexPath; - (NSString*) nameForDataSourceSectionAtIndex:(NSInteger)section;
@property (weak) id<ChainableDataSourceDelegate> dataSourceDelegate;
@end
![Page 21: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/21.jpg)
🍓
🍆
💵
M
![Page 22: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/22.jpg)
🍓
🍆
💵
M
NSArray (ChainableDataSource)
FetchedResultsDataSource
<#YourChainableDataSource#>
![Page 23: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/23.jpg)
MCV
🍓
🍆
+
💵
<
🍓
🍓
🍆
🍓
💵
🍆
![Page 24: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/24.jpg)
![Page 25: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/25.jpg)
🍓
CellDataSource
![Page 26: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/26.jpg)
🍓
CellDataSource
@interface CellDataSource : NSObject <ChainableDataSource, UITableViewDataSource> - (NSString*) cellIdentifierForObject:(id)object; - (void) configureCell:(UIView<GenericCell>*)cell withObject:(id)object;
![Page 27: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/27.jpg)
MCV
🍓
🍆
+
💵
<
🍓
🍓
🍆
🍓
💵
🍆
![Page 28: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/28.jpg)
+
<
![Page 29: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/29.jpg)
+
<
<#YourChainableDataSource#>
![Page 30: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/30.jpg)
+
<
TransformDataSource<#YourChainableDataSource#>
![Page 31: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/31.jpg)
@interface TransformDataSource : NSObject <ChainableDataSource>
@property (nonatomic, copy) NSArray<id<ChainableDataSource>>* dataSources;
- (NSIndexPath*) sourceIndexPathForIndexPath:(NSIndexPath*)indexPath;
- (NSIndexPath*) indexPathForSourceIndexPath:(NSIndexPath*)sourceIndexPath inDataSource:(id<ChainableDataSource>)sourceDataSource;
- (NSInteger) sectionIndexForSourceSectionIndex:(NSInteger)sourceSection inDataSource:(id<ChainableDataSource>)sourceDataSource;
- (NSIndexPath*) sourceSectionIndexPathForSectionIndex:(NSInteger)section;
@end
![Page 32: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/32.jpg)
+
<
TransformDataSource<#YourChainableDataSource#>
![Page 33: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/33.jpg)
+
TransformDataSource<#YourChainableDataSource#>
ConcatenatedSectionsDataSource
![Page 34: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/34.jpg)
<
TransformDataSource<#YourChainableDataSource#>
ConcatenatedSectionsDataSourceInsertionDataSource
![Page 35: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/35.jpg)
TransformDataSource<#YourChainableDataSource#>
ConcatenatedSectionsDataSourceInsertionDataSource
🎉SwitchDataSourceFlattenedDataSource
FilterDataSourcePlaceholderDataSource
EmptySectionFilterDataSource<#YourTransformDataSource#>
![Page 36: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/36.jpg)
Updates
![Page 37: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/37.jpg)
MCV
🍓
🍆
+
💵
<
🍓
🍓
🍆
🍓
💵
🍆
![Page 38: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/38.jpg)
🍓
🍆
+
💵
<
🍓
🍓
🍆
🍓
💵
🍆
ChainableDataSourceDelegate
![Page 39: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/39.jpg)
@protocol ChainableDataSourceDelegate <NSObject>
- (void) dataSourceDidReload:(id<ChainableDataSource>)dataSource; - (void) dataSourceWillUpdate:(id<ChainableDataSource>)dataSource; - (void) dataSourceDidUpdate:(id<ChainableDataSource>)dataSource;
- (void) dataSource:(id<ChainableDataSource>)dataSource didDeleteSectionsAtIndexes:(NSIndexSet*)sectionIndexes; - (void) dataSource:(id<ChainableDataSource>)dataSource didInsertSectionsAtIndexes:(NSIndexSet*)sectionIndexes; - (void) dataSource:(id<ChainableDataSource>)dataSource didDeleteObjectsAtIndexPaths:(NSArray<NSIndexPath*>*)indexPath; - (void) dataSource:(id<ChainableDataSource>)dataSource didInsertObjectsAtIndexPaths:(NSArray<NSIndexPath*>*)indexPath; - (void) dataSource:(id<ChainableDataSource>)dataSource didUpdateObjectsAtIndexPaths:(NSArray<NSIndexPath*>*)indexPath;
@end
![Page 40: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/40.jpg)
A
B
E
D
C
F
A
C
H
D
G
The truth about updates
![Page 41: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/41.jpg)
A
B
E
D
C
F
A
C
H
D
G
The truth about updatesdelete: 1, 4, 5 insert: 2, 4
![Page 42: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/42.jpg)
A
B
E
D
C
F
A
C
H
D
G
The truth about updatesupdate: 1
![Page 43: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/43.jpg)
[tableView beginUpdates]; [self.fruits removeObjectAtIndex:indexPath.row]; [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; [tableView endUpdates]; //OK
The truth about updates
![Page 44: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/44.jpg)
[tableView beginUpdates]; [self.fruits removeObjectAtIndex:indexPath.row]; [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; [tableView endUpdates]; //Still OK
The truth about updates
![Page 45: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/45.jpg)
🍓
🍆
+
💵
<
🍓
🍓
🍆
🍓
💵
🍆
ChainableDataSourceDelegate
![Page 46: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/46.jpg)
🍓
🍓
🍆
🍓
💵
🍆
UITableView <ChainableDataSourceDelegate>UICollectionView <ChainableDataSourceDelegate>
![Page 47: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/47.jpg)
🍓
🍆
+
💵
<
🍓
🍓
🍆
🍓
💵
🍆
ChainableDataSourceDelegate
![Page 48: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/48.jpg)
CellDataSource
didUpdateObjectsAtIndexPaths -> configureCell:withObject: everything else -> forward
![Page 49: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/49.jpg)
🍓
🍆
+
💵
<
🍓
🍓
🍆
🍓
💵
🍆
ChainableDataSourceDelegate
![Page 50: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/50.jpg)
🍓
🍆
💵
<#YourChainableDataSource#>
FetchedResultsDatasource
![Page 51: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/51.jpg)
🍓
🍆
+
💵
<
🍓
🍓
🍆
🍓
💵
🍆
ChainableDataSourceDelegate
![Page 52: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/52.jpg)
+
<
basic mapping -> automatic
TransformDataSource
![Page 53: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/53.jpg)
TransformDataSource
advanced mapping: tweak update set pre and post upstream updates
- (void) preRefreshTranslateSourceUpdateCache:(UpdateCache*)sourceUpdateCache fromDataSource:(id<ChainableDataSource>)dataSource toUpdateCache:(UpdateCache*)updateCache;
- (void) postRefreshTranslateSourceUpdateCache:(UpdateCache*)sourceUpdateCache fromDataSource:(id<ChainableDataSource>)dataSource toUpdateCache:(UpdateCache*)updateCache;
![Page 54: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/54.jpg)
🍓
🍓
🍓
🍓
🍓
🍓
🍓
dataSourceDidReload
![Page 55: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/55.jpg)
🍓
🍓
🍓
🍓
🍓
🍓
🍓
dataSourceDidReloaddataSourceDidReload (reloadData - 😥 )
![Page 56: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/56.jpg)
🍓Δ
🍓
🍓
🍓
🍓
🍓
🍓
DeltaUpdateDataSource
dataSourceDidReload
![Page 57: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/57.jpg)
A
B
E
D
C
F
A
C
H
D
G
![Page 58: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/58.jpg)
A
B
E
D
C
F
A
C
H
D
G- = ?
![Page 59: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/59.jpg)
A
B
E
D
C
F
A
C
H
D
G
delete: 1, 4, 5 insert: 2, 4
diff algorithm Longest Common Subsequence
![Page 60: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/60.jpg)
🍓Δ
🍓
🍓
🍓
🍓
🍓
🍓
DeltaUpdateDataSource
dataSourceDidReload
![Page 61: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/61.jpg)
🍓Δ
🍓
🍓
🍓
🍓
🍓
🍓
DeltaUpdateDataSource
dataSourceDidReload
dataSourceWillUpdate dataSource…∆ dataSourceDidUpdate😁
![Page 62: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/62.jpg)
Updates//TODO: Nothing
![Page 63: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/63.jpg)
🍓
🍆
+
💵
<
🍓
🍓
🍆
🍓
💵
🍆
CellDataSource
![Page 64: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/64.jpg)
CellDataSource
- (NSString*) cellIdentifierForObject:(id)object { return NSStringFromClass([object class]); }
- (void) configureCell:(UITableViewCell*)cell withObject:(id)object { if ([cell.reuseIdentifier isEqual:@"Fruit"]) { //... } else if ([cell.reuseIdentifier isEqual:@"Vegetable"]) { //... } //😢 }
![Page 65: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/65.jpg)
🍓
🍆
+
💵
<
🍓
🍓
🍆
🍓
💵
🍆
CellDataSource
![Page 66: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/66.jpg)
🍓
🍆
+
💵
<
🍓
🍓
🍆
🍓
💵
🍆
CellDataSource: alternative approach
![Page 67: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/67.jpg)
🍓
🍆
+
💵
<
🍓
🍓
🍆
🍓
💵
🍆
TransformDataSource (CellDataSource) forward delegate/data source methods
based on index mapping
![Page 68: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/68.jpg)
TransformDataSource (CellDataSource) forward delegate/data source methods
based on index mapping
(My dirty secret)
![Page 69: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/69.jpg)
- (void) forwardInvocation:(NSInvocation *)anInvocation { if ([self isForwardableDelegateSelector:anInvocation.selector]) { NSMethodSignature* signature = anInvocation.methodSignature; NSArray* components = [NSStringFromSelector(anInvocation.selector)componentsSeparatedByString:@":"]; for (NSInteger argIndex = 0; argIndex < signature.numberOfArguments; argIndex++) { //skip self and cmd if (argIndex < 2) { continue; } //won't work with targetIndexPathForMoveFromRowAtIndexPath, since two indexPath are present const char* argType = [signature getArgumentTypeAtIndex:argIndex]; if (strcmp(argType, @encode(NSIndexPath*)) == 0) { __unsafe_unretained id arg; [anInvocation getArgument:&arg atIndex:argIndex]; if ([arg isKindOfClass:[NSIndexPath class]]) { NSIndexPath* indexPath = arg; NSIndexPath* fullIndexPath = [self sourceIndexPathForIndexPath:indexPath]; id<ChainableDataSource> dataSource = self.dataSources[[fullIndexPath indexAtPosition:0]]; NSIndexPath* dsIndexPath = [NSIndexPath indexPathForRow:[fullIndexPath indexAtPosition:2] inSection:[fullIndexPath indexAtPosition:1]]; [anInvocation setArgument:&dsIndexPath atIndex:argIndex]; if ([dataSource respondsToSelector:anInvocation.selector]) { [anInvocation invokeWithTarget:dataSource]; } return; } } else if (strcmp(argType, @encode(NSInteger)) == 0 && [components[argIndex-2] hasSuffix:@"Section"]) { NSInteger section; [anInvocation getArgument:§ion atIndex:argIndex]; NSIndexPath* sourceSectionIndexPath = [self sourceSectionIndexPathForSectionIndex:section]; if (sourceSectionIndexPath) { id<ChainableDataSource> dataSource = self.dataSources[[sourceSectionIndexPath indexAtPosition:0]]; NSInteger sourceSection = [sourceSectionIndexPath indexAtPosition:1]; [anInvocation setArgument:&sourceSection atIndex:argIndex]; if ([dataSource respondsToSelector:anInvocation.selector]) { [anInvocation invokeWithTarget:dataSource]; } } return; } } return; } return [super forwardInvocation:anInvocation]; }
![Page 70: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/70.jpg)
🍓
🍆
+
💵
<
🍓
🍓
🍆
🍓
💵
🍆
![Page 71: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/71.jpg)
CellDataSource
@implementation FruitCellDataSource - (NSString*) cellIdentifierForObject:(id)object { return @"fruit-cell"; }
- (void) configureCell:(UITableViewCell*)cell withObject:(id)object { Fruit* fruit = object; cell.titleLabel.text = fruit.name; }
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { Fruit* fruit = [self.objectsDataSource dataSourceObjectAtIndexPath:indexPath]; //... } @end
![Page 72: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/72.jpg)
🍓
🍆
+
💵
<
🍓
🍓
🍆
🍓
💵
🍆
It’s alive!
![Page 73: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/73.jpg)
Demo
![Page 74: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/74.jpg)
Open source*
![Page 75: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/75.jpg)
*before this holiday season
Open source*
![Page 76: Chainable datasource](https://reader034.vdocuments.mx/reader034/viewer/2022052606/586e859e1a28aba0038b6429/html5/thumbnails/76.jpg)
?
amadour