|
13 | 13 | #import "YLTableView.h"
|
14 | 14 | #import "YLTableViewPrivate.h"
|
15 | 15 | #import "YLTableViewCell.h"
|
16 |
| -#import "YLTableViewCellPrivate.h" |
17 | 16 | #import "YLTableViewChildViewControllerCell.h"
|
18 | 17 | #import "YLTableViewSectionHeaderFooterView.h"
|
19 | 18 | #import "YLTableViewSectionHeaderFooterViewPrivate.h"
|
20 | 19 |
|
| 20 | +@interface YLTableViewDataSource () |
| 21 | + |
| 22 | +//! This is used to cache the estimated row heights. |
| 23 | +@property (strong, nonatomic) NSMutableDictionary<NSString *, NSNumber *> * indexPathToEstimatedRowHeight; |
| 24 | + |
| 25 | +@end |
| 26 | + |
21 | 27 | @implementation YLTableViewDataSource
|
22 | 28 |
|
| 29 | + |
| 30 | +#pragma mark indexPathToEstimatedRowHeight property methods |
| 31 | + |
| 32 | +- (NSMutableDictionary<NSString *,NSNumber *> *)indexPathToEstimatedRowHeight { |
| 33 | + if (!_indexPathToEstimatedRowHeight) { |
| 34 | + _indexPathToEstimatedRowHeight = [[NSMutableDictionary alloc] init]; |
| 35 | + } |
| 36 | + |
| 37 | + return _indexPathToEstimatedRowHeight; |
| 38 | +} |
| 39 | + |
23 | 40 | #pragma mark Public Helpers
|
24 | 41 |
|
25 | 42 | - (void)reloadVisibleCellForModel:(id)model inTableView:(UITableView *)tableView {
|
26 | 43 | for (NSIndexPath *indexPath in [tableView indexPathsForVisibleRows]) {
|
27 | 44 | if ([self tableView:tableView modelForCellAtIndexPath:indexPath] == model) {
|
28 |
| - [(YLTableViewCell *)[tableView cellForRowAtIndexPath:indexPath] setModel:model]; |
| 45 | + [(UITableViewCell<YLTableViewCell> *)[tableView cellForRowAtIndexPath:indexPath] setModel:model]; |
29 | 46 | return;
|
30 | 47 | }
|
31 | 48 | }
|
32 | 49 | }
|
33 | 50 |
|
| 51 | +#pragma mark Private Helpers |
| 52 | + |
| 53 | +//! Constructs a cache key for the given index path. UITableView sometimes returns a different subclass, NSMutableIndexPath, so we can't use the index path as the key by itself. |
| 54 | ++ (NSString *)_keyForIndexPath:(NSIndexPath *)indexPath { |
| 55 | + return [NSString stringWithFormat:@"%ld,%ld", (long)indexPath.section, (long)indexPath.row]; |
| 56 | +} |
| 57 | + |
34 | 58 | #pragma mark Configuration
|
35 | 59 |
|
36 |
| -- (void)tableView:(UITableView *)tableView configureCell:(YLTableViewCell *)cell forIndexPath:(NSIndexPath *)indexPath { |
| 60 | +- (void)tableView:(UITableView *)tableView configureCell:(UITableViewCell<YLTableViewCell> *)cell forIndexPath:(NSIndexPath *)indexPath { |
37 | 61 | [cell setModel:[self tableView:tableView modelForCellAtIndexPath:indexPath]];
|
38 | 62 | }
|
39 | 63 |
|
@@ -77,7 +101,7 @@ - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger
|
77 | 101 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
78 | 102 | NSString *const reuseID = [self tableView:tableView reuseIdentifierForCellAtIndexPath:indexPath];
|
79 | 103 | NSAssert(reuseID != nil, @"Must have a reuse identifier.");
|
80 |
| - YLTableViewCell *cell = (YLTableViewCell *)[tableView dequeueReusableCellWithIdentifier:reuseID forIndexPath:indexPath]; |
| 104 | + UITableViewCell<YLTableViewCell> *cell = (UITableViewCell<YLTableViewCell> *)[tableView dequeueReusableCellWithIdentifier:reuseID forIndexPath:indexPath]; |
81 | 105 | [self tableView:tableView configureCell:cell forIndexPath:indexPath];
|
82 | 106 | return cell;
|
83 | 107 | }
|
@@ -112,16 +136,7 @@ - (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger
|
112 | 136 |
|
113 | 137 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
|
114 | 138 | NSAssert([tableView isKindOfClass:[YLTableView class]], @"This can only be the delegate of a YLTableView.");
|
115 |
| - |
116 |
| - if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0) { |
117 |
| - return UITableViewAutomaticDimension; |
118 |
| - } |
119 |
| - |
120 |
| - NSString *const reuseID = [self tableView:tableView reuseIdentifierForCellAtIndexPath:indexPath]; |
121 |
| - YLTableViewCell *cell = [(YLTableView *)tableView sizingCellForReuseIdentifier:reuseID]; |
122 |
| - [self tableView:tableView configureCell:cell forIndexPath:indexPath]; |
123 |
| - |
124 |
| - return [cell heightForWidth:CGRectGetWidth(tableView.bounds) separatorStyle:tableView.separatorStyle]; |
| 139 | + return UITableViewAutomaticDimension; |
125 | 140 | }
|
126 | 141 |
|
127 | 142 | - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
|
@@ -152,9 +167,26 @@ - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSIntege
|
152 | 167 | }
|
153 | 168 | }
|
154 | 169 |
|
| 170 | +- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath { |
| 171 | + NSAssert([tableView isKindOfClass:[YLTableView class]], @"This can only be the delegate of a YLTableView."); |
| 172 | + |
| 173 | + if (self.shouldCacheEstimatedRowHeights && self.indexPathToEstimatedRowHeight[[[self class] _keyForIndexPath:indexPath]]) { |
| 174 | + return [self.indexPathToEstimatedRowHeight[[[self class] _keyForIndexPath:indexPath]] floatValue]; |
| 175 | + } |
| 176 | + |
| 177 | + Class cellClass = NSClassFromString([self tableView:tableView reuseIdentifierForCellAtIndexPath:indexPath]); |
| 178 | + NSAssert([cellClass conformsToProtocol:@protocol(YLTableViewCell)], @"You can only use cells conforming to YLTableViewCell."); |
| 179 | + return [(id<YLTableViewCell>)cellClass estimatedRowHeight]; |
| 180 | +} |
| 181 | + |
155 | 182 | #pragma mark ChildViewController support
|
156 | 183 |
|
157 | 184 | - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
|
| 185 | + |
| 186 | + if (self.shouldCacheEstimatedRowHeights) { |
| 187 | + self.indexPathToEstimatedRowHeight[[[self class] _keyForIndexPath:indexPath]] = @(cell.frame.size.height); |
| 188 | + } |
| 189 | + |
158 | 190 | UIViewController *parentViewController = self.parentViewController;
|
159 | 191 | if ([cell conformsToProtocol:@protocol(YLTableViewChildViewControllerCell)]) {
|
160 | 192 | NSAssert(parentViewController != nil, @"Must have a parent view controller to support cell %@", cell);
|
|
0 commit comments