2323#import " UITableView+FDIndexPathHeightCache.h"
2424#import < objc/runtime.h>
2525
26+ typedef NSMutableArray <NSMutableArray <NSNumber *> *> FDIndexPathHeightsBySection;
27+
2628@interface FDIndexPathHeightCache ()
27- @property (nonatomic , strong ) NSMutableArray *heightsBySectionForPortrait;
28- @property (nonatomic , strong ) NSMutableArray *heightsBySectionForLandscape;
29+ @property (nonatomic , strong ) FDIndexPathHeightsBySection *heightsBySectionForPortrait;
30+ @property (nonatomic , strong ) FDIndexPathHeightsBySection *heightsBySectionForLandscape;
2931@end
3032
3133@implementation FDIndexPathHeightCache
@@ -39,11 +41,11 @@ - (instancetype)init {
3941 return self;
4042}
4143
42- - (NSMutableArray *)heightsBySectionForCurrentOrientation {
44+ - (FDIndexPathHeightsBySection *)heightsBySectionForCurrentOrientation {
4345 return UIDeviceOrientationIsPortrait ([UIDevice currentDevice ].orientation ) ? self.heightsBySectionForPortrait : self.heightsBySectionForLandscape ;
4446}
4547
46- - (void )enumerateAllOrientationsUsingBlock : (void (^)(NSMutableArray *heightsBySection))block {
48+ - (void )enumerateAllOrientationsUsingBlock : (void (^)(FDIndexPathHeightsBySection *heightsBySection))block {
4749 block (self.heightsBySectionForPortrait );
4850 block (self.heightsBySectionForLandscape );
4951}
@@ -72,13 +74,13 @@ - (CGFloat)heightForIndexPath:(NSIndexPath *)indexPath {
7274
7375- (void )invalidateHeightAtIndexPath : (NSIndexPath *)indexPath {
7476 [self buildCachesAtIndexPathsIfNeeded: @[indexPath]];
75- [self enumerateAllOrientationsUsingBlock: ^(NSMutableArray *heightsBySection) {
77+ [self enumerateAllOrientationsUsingBlock: ^(FDIndexPathHeightsBySection *heightsBySection) {
7678 heightsBySection[indexPath.section][indexPath.row] = @-1 ;
7779 }];
7880}
7981
8082- (void )invalidateAllHeightCache {
81- [self enumerateAllOrientationsUsingBlock: ^(NSMutableArray *heightsBySection) {
83+ [self enumerateAllOrientationsUsingBlock: ^(FDIndexPathHeightsBySection *heightsBySection) {
8284 [heightsBySection removeAllObjects ];
8385 }];
8486}
@@ -92,7 +94,7 @@ - (void)buildCachesAtIndexPathsIfNeeded:(NSArray *)indexPaths {
9294}
9395
9496- (void )buildSectionsIfNeeded : (NSInteger )targetSection {
95- [self enumerateAllOrientationsUsingBlock: ^(NSMutableArray *heightsBySection) {
97+ [self enumerateAllOrientationsUsingBlock: ^(FDIndexPathHeightsBySection *heightsBySection) {
9698 for (NSInteger section = 0 ; section <= targetSection; ++section) {
9799 if (section >= heightsBySection.count ) {
98100 heightsBySection[section] = [NSMutableArray array ];
@@ -102,8 +104,8 @@ - (void)buildSectionsIfNeeded:(NSInteger)targetSection {
102104}
103105
104106- (void )buildRowsIfNeeded : (NSInteger )targetRow inExistSection : (NSInteger )section {
105- [self enumerateAllOrientationsUsingBlock: ^(NSMutableArray *heightsBySection) {
106- NSMutableArray *heightsByRow = heightsBySection[section];
107+ [self enumerateAllOrientationsUsingBlock: ^(FDIndexPathHeightsBySection *heightsBySection) {
108+ NSMutableArray < NSNumber *> *heightsByRow = heightsBySection[section];
107109 for (NSInteger row = 0 ; row <= targetRow; ++row) {
108110 if (row >= heightsByRow.count ) {
109111 heightsByRow[row] = @-1 ;
@@ -128,10 +130,18 @@ - (FDIndexPathHeightCache *)fd_indexPathHeightCache {
128130
129131@end
130132
133+ // We just for forward primary call, in crash report, top most method in stack maybe FD's,
134+ // but it's not our bug, you should check whether your table view's data source and displaying
135+ // cells are not match when reloading.
136+ static void __FD_TEMPLATE_LAYOUT_CELL_PRIMARY_CALL_IF_CRASH_NOT_OUR_BUG__ (void (^callout)(void )) {
137+ callout ();
138+ }
139+ #define FDPrimaryCall (...) do {__FD_TEMPLATE_LAYOUT_CELL_PRIMARY_CALL_IF_CRASH_NOT_OUR_BUG__ (^{__VA_ARGS__});} while (0 )
140+
131141@implementation UITableView (FDIndexPathHeightCacheInvalidation)
132142
133143- (void )fd_reloadDataWithoutInvalidateIndexPathHeightCache {
134- [self fd_reloadData ]; // Primary call only
144+ FDPrimaryCall ( [self fd_reloadData ];);
135145}
136146
137147+ (void )load {
@@ -159,79 +169,78 @@ + (void)load {
159169
160170- (void )fd_reloadData {
161171 if (self.fd_indexPathHeightCache .automaticallyInvalidateEnabled ) {
162- [self .fd_indexPathHeightCache enumerateAllOrientationsUsingBlock: ^(NSMutableArray *heightsBySection) {
172+ [self .fd_indexPathHeightCache enumerateAllOrientationsUsingBlock: ^(FDIndexPathHeightsBySection *heightsBySection) {
163173 [heightsBySection removeAllObjects ];
164174 }];
165175 }
166- [self fd_reloadData ]; // Primary call
176+ FDPrimaryCall ( [self fd_reloadData ];);
167177}
168178
169179- (void )fd_insertSections : (NSIndexSet *)sections withRowAnimation : (UITableViewRowAnimation)animation {
170180 if (self.fd_indexPathHeightCache .automaticallyInvalidateEnabled ) {
171181 [sections enumerateIndexesUsingBlock: ^(NSUInteger section, BOOL *stop) {
172182 [self .fd_indexPathHeightCache buildSectionsIfNeeded: section];
173- [self .fd_indexPathHeightCache enumerateAllOrientationsUsingBlock: ^(NSMutableArray *heightsBySection) {
183+ [self .fd_indexPathHeightCache enumerateAllOrientationsUsingBlock: ^(FDIndexPathHeightsBySection *heightsBySection) {
174184 [heightsBySection insertObject: [NSMutableArray array ] atIndex: section];
175185 }];
176186 }];
177187 }
178- [self fd_insertSections: sections withRowAnimation: animation]; // Primary call
188+ FDPrimaryCall ( [self fd_insertSections: sections withRowAnimation: animation];);
179189}
180190
181191- (void )fd_deleteSections : (NSIndexSet *)sections withRowAnimation : (UITableViewRowAnimation)animation {
182192 if (self.fd_indexPathHeightCache .automaticallyInvalidateEnabled ) {
183193 [sections enumerateIndexesUsingBlock: ^(NSUInteger section, BOOL *stop) {
184194 [self .fd_indexPathHeightCache buildSectionsIfNeeded: section];
185- [self .fd_indexPathHeightCache enumerateAllOrientationsUsingBlock: ^(NSMutableArray *heightsBySection) {
195+ [self .fd_indexPathHeightCache enumerateAllOrientationsUsingBlock: ^(FDIndexPathHeightsBySection *heightsBySection) {
186196 [heightsBySection removeObjectAtIndex: section];
187197 }];
188198 }];
189199 }
190- [self fd_deleteSections: sections withRowAnimation: animation]; // Primary call
200+ FDPrimaryCall ( [self fd_deleteSections: sections withRowAnimation: animation];);
191201}
192202
193203- (void )fd_reloadSections : (NSIndexSet *)sections withRowAnimation : (UITableViewRowAnimation)animation {
194204 if (self.fd_indexPathHeightCache .automaticallyInvalidateEnabled ) {
195205 [sections enumerateIndexesUsingBlock: ^(NSUInteger section, BOOL *stop) {
196206 [self .fd_indexPathHeightCache buildSectionsIfNeeded: section];
197- [self .fd_indexPathHeightCache enumerateAllOrientationsUsingBlock: ^(NSMutableArray *heightsBySection) {
207+ [self .fd_indexPathHeightCache enumerateAllOrientationsUsingBlock: ^(FDIndexPathHeightsBySection *heightsBySection) {
198208 [heightsBySection[section] removeAllObjects ];
199209 }];
200210
201211 }];
202212 }
203- [self fd_reloadSections: sections withRowAnimation: animation]; // Primary call
213+ FDPrimaryCall ( [self fd_reloadSections: sections withRowAnimation: animation];);
204214}
205215
206216- (void )fd_moveSection : (NSInteger )section toSection : (NSInteger )newSection {
207217 if (self.fd_indexPathHeightCache .automaticallyInvalidateEnabled ) {
208218 [self .fd_indexPathHeightCache buildSectionsIfNeeded: section];
209219 [self .fd_indexPathHeightCache buildSectionsIfNeeded: newSection];
210- [self .fd_indexPathHeightCache enumerateAllOrientationsUsingBlock: ^(NSMutableArray *heightsBySection) {
220+ [self .fd_indexPathHeightCache enumerateAllOrientationsUsingBlock: ^(FDIndexPathHeightsBySection *heightsBySection) {
211221 [heightsBySection exchangeObjectAtIndex: section withObjectAtIndex: newSection];
212222 }];
213223 }
214- [self fd_moveSection: section toSection: newSection]; // Primary call
224+ FDPrimaryCall ( [self fd_moveSection: section toSection: newSection];);
215225}
216226
217- - (void )fd_insertRowsAtIndexPaths : (NSArray *)indexPaths withRowAnimation : (UITableViewRowAnimation)animation {
227+ - (void )fd_insertRowsAtIndexPaths : (NSArray <NSIndexPath *> *)indexPaths withRowAnimation : (UITableViewRowAnimation)animation {
218228 if (self.fd_indexPathHeightCache .automaticallyInvalidateEnabled ) {
219229 [self .fd_indexPathHeightCache buildCachesAtIndexPathsIfNeeded: indexPaths];
220230 [indexPaths enumerateObjectsUsingBlock: ^(NSIndexPath *indexPath, NSUInteger idx, BOOL *stop) {
221- [self .fd_indexPathHeightCache enumerateAllOrientationsUsingBlock: ^(NSMutableArray *heightsBySection) {
222- NSMutableArray *rows = heightsBySection[indexPath.section];
223- [rows insertObject: @-1 atIndex: indexPath.row];
231+ [self .fd_indexPathHeightCache enumerateAllOrientationsUsingBlock: ^(FDIndexPathHeightsBySection *heightsBySection) {
232+ [heightsBySection[indexPath.section] insertObject: @-1 atIndex: indexPath.row];
224233 }];
225234 }];
226235 }
227- [self fd_insertRowsAtIndexPaths: indexPaths withRowAnimation: animation]; // Primary call
236+ FDPrimaryCall ( [self fd_insertRowsAtIndexPaths: indexPaths withRowAnimation: animation];);
228237}
229238
230- - (void )fd_deleteRowsAtIndexPaths : (NSArray *)indexPaths withRowAnimation : (UITableViewRowAnimation)animation {
239+ - (void )fd_deleteRowsAtIndexPaths : (NSArray <NSIndexPath *> *)indexPaths withRowAnimation : (UITableViewRowAnimation)animation {
231240 if (self.fd_indexPathHeightCache .automaticallyInvalidateEnabled ) {
232241 [self .fd_indexPathHeightCache buildCachesAtIndexPathsIfNeeded: indexPaths];
233242
234- NSMutableDictionary *mutableIndexSetsToRemove = [NSMutableDictionary dictionary ];
243+ NSMutableDictionary < NSNumber *, NSMutableIndexSet *> *mutableIndexSetsToRemove = [NSMutableDictionary dictionary ];
235244 [indexPaths enumerateObjectsUsingBlock: ^(NSIndexPath *indexPath, NSUInteger idx, BOOL *stop) {
236245 NSMutableIndexSet *mutableIndexSet = mutableIndexSetsToRemove[@(indexPath.section)];
237246 if (!mutableIndexSet) {
@@ -242,41 +251,39 @@ - (void)fd_deleteRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITabl
242251 }];
243252
244253 [mutableIndexSetsToRemove enumerateKeysAndObjectsUsingBlock: ^(NSNumber *key, NSIndexSet *indexSet, BOOL *stop) {
245- [self .fd_indexPathHeightCache enumerateAllOrientationsUsingBlock: ^(NSMutableArray *heightsBySection) {
246- NSMutableArray *rows = heightsBySection[key.integerValue];
247- [rows removeObjectsAtIndexes: indexSet];
254+ [self .fd_indexPathHeightCache enumerateAllOrientationsUsingBlock: ^(FDIndexPathHeightsBySection *heightsBySection) {
255+ [heightsBySection[key.integerValue] removeObjectsAtIndexes: indexSet];
248256 }];
249257 }];
250258 }
251- [self fd_deleteRowsAtIndexPaths: indexPaths withRowAnimation: animation]; // Primary call
259+ FDPrimaryCall ( [self fd_deleteRowsAtIndexPaths: indexPaths withRowAnimation: animation];);
252260}
253261
254- - (void )fd_reloadRowsAtIndexPaths : (NSArray *)indexPaths withRowAnimation : (UITableViewRowAnimation)animation {
262+ - (void )fd_reloadRowsAtIndexPaths : (NSArray <NSIndexPath *> *)indexPaths withRowAnimation : (UITableViewRowAnimation)animation {
255263 if (self.fd_indexPathHeightCache .automaticallyInvalidateEnabled ) {
256264 [self .fd_indexPathHeightCache buildCachesAtIndexPathsIfNeeded: indexPaths];
257265 [indexPaths enumerateObjectsUsingBlock: ^(NSIndexPath *indexPath, NSUInteger idx, BOOL *stop) {
258- [self .fd_indexPathHeightCache enumerateAllOrientationsUsingBlock: ^(NSMutableArray *heightsBySection) {
259- NSMutableArray *rows = heightsBySection[indexPath.section];
260- rows[indexPath.row] = @-1 ;
266+ [self .fd_indexPathHeightCache enumerateAllOrientationsUsingBlock: ^(FDIndexPathHeightsBySection *heightsBySection) {
267+ heightsBySection[indexPath.section][indexPath.row] = @-1 ;
261268 }];
262269 }];
263270 }
264- [self fd_reloadRowsAtIndexPaths: indexPaths withRowAnimation: animation]; // Primary call
271+ FDPrimaryCall ( [self fd_reloadRowsAtIndexPaths: indexPaths withRowAnimation: animation];);
265272}
266273
267274- (void )fd_moveRowAtIndexPath : (NSIndexPath *)sourceIndexPath toIndexPath : (NSIndexPath *)destinationIndexPath {
268275 if (self.fd_indexPathHeightCache .automaticallyInvalidateEnabled ) {
269276 [self .fd_indexPathHeightCache buildCachesAtIndexPathsIfNeeded: @[sourceIndexPath, destinationIndexPath]];
270- [self .fd_indexPathHeightCache enumerateAllOrientationsUsingBlock: ^(NSMutableArray *heightsBySection) {
271- NSMutableArray *sourceRows = heightsBySection[sourceIndexPath.section];
272- NSMutableArray *destinationRows = heightsBySection[destinationIndexPath.section];
277+ [self .fd_indexPathHeightCache enumerateAllOrientationsUsingBlock: ^(FDIndexPathHeightsBySection *heightsBySection) {
278+ NSMutableArray < NSNumber *> *sourceRows = heightsBySection[sourceIndexPath.section];
279+ NSMutableArray < NSNumber *> *destinationRows = heightsBySection[destinationIndexPath.section];
273280 NSNumber *sourceValue = sourceRows[sourceIndexPath.row];
274281 NSNumber *destinationValue = destinationRows[destinationIndexPath.row];
275282 sourceRows[sourceIndexPath.row] = destinationValue;
276283 destinationRows[destinationIndexPath.row] = sourceValue;
277284 }];
278285 }
279- [self fd_moveRowAtIndexPath: sourceIndexPath toIndexPath: destinationIndexPath]; // Primary call
286+ FDPrimaryCall ( [self fd_moveRowAtIndexPath: sourceIndexPath toIndexPath: destinationIndexPath];);
280287}
281288
282289@end
0 commit comments