項目中有個類似微博那樣的動態cell,文字和圖片的多少都不是確定的
剛開始使用autolayout,結果很多問題,最後我發現了一個框架 FDTemplateLayoutCell
寫的很好,自動布局cell,但是最後還是出現了很多問題,或許是不適用這種情況
最後只能用frame布局了,但是FDTemplateLayoutCell的緩存機制還是值得借鑒的
說說我的做法
首先利用frameModel計算出cell height
這個過程省略
我說說這麼緩存
和FD*一樣,我寫了一個UITableView的category
在這個category裡面又寫了一個類,CellHeightCache
定義了三個方法
//是否已經緩存了
- (BOOL)existsHeightForKey:(id<NSCopying>)key { NSNumber *number = self.mutableCellHeightCaches[key]; return number && ![number isEqualToNumber:@-1]; }
//緩存高度,傳入key - (void)cacheHeight:(CGFloat)height byKey:(id<NSCopying>)key { self.mutableCellHeightCaches[key] = @(height); }
//傳入key獲得高度 - (CGFloat)heightForKey:(id<NSCopying>)key { #if CGFLOAT_IS_DOUBLE return [self.mutableCellHeightCaches[key] doubleValue]; #else return [self.mutableCellHeightCaches[key] floatValue]; #endif }
然後我在UITableView的分類裡面寫了兩個方法
一個傳入key獲得高度,一個傳入key和高度 緩存高度
- (CGFloat)getCellHeightCacheWithCacheKey:(NSString *)cacheKey { if (!cacheKey) { return 0; } //如果已經存在cell height 則返回 if ([self.cellHeightCache existsHeightForKey:cacheKey]) { CGFloat cachedHeight = [self.cellHeightCache heightForKey:cacheKey]; return cachedHeight; } else { return 0; } } //緩存cell的高度 - (void)setCellHeightCacheWithCellHeight:(CGFloat)cellHeight CacheKey:(NSString *)cacheKey { [self.cellHeightCache cacheHeight:cellHeight byKey:cacheKey]; }
他們都調用了這個方法
- (CellHeightCache *)cellHeightCache { CellHeightCache *cache = objc_getAssociatedObject(self, _cmd); if (!cache) { cache = [CellHeightCache new]; objc_setAssociatedObject(self, _cmd, cache, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } return cache; }
這兩個方法用的是OC中runtime方法,原理是兩個文件關聯方法,和上層的存儲方法> 差不多,傳入value和key對應,取出也是根據key取出value
object傳入self即可
1.設置關聯方法
//傳入object和key和value,policy //policy即存儲方式,和聲明使用幾種屬性大致相同,有copy,retain,copy,retain_nonatomic,assign 五種) void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
2.取出方法
//傳入object和key返回value id objc_getAssociatedObject(id object, const void *key)
這裡是先獲得緩存對象,如果為空的還就新創建一個,再進行關聯。
這裡用到了_cmd
_cmd是隱藏的參數,代表當前方法的selector,他和self一樣都是每個方法調用時都會傳入的參數,動態運行時會提及如何傳的這兩個參數。
經常和關聯方法搭配一起用
然後我在heightForRowAtIndexPath裡面調用了
CGFloat cellHeight = [tableView getCellHeightCacheWithCacheKey:statusFrame.identifier]; NSLog(@"從緩存取出來的-----%f",cellHeight); if(!cellHeight){ statusFrame.status = status; cellHeight = statusFrame.cellHeight; [tableView setCellHeightCacheWithCellHeight:cellHeight CacheKey:statusFrame.identifier]; }
這樣緩存高度就搞定了。
實際效果
代碼地址
https://github.com/AscenZ/YBDynamicCell
我寫的一篇 解析FDTempLayoutCell的文章