zoukankan      html  css  js  c++  java
  • iOS开发之计算动态cell的高度并缓存

    项目中有个类似微博那样的动态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的文章

    在公众号

  • 相关阅读:
    java知识总结-15
    java知识总结-14
    java知识总结-13
    Java知识总结-12
    Java知识总结-11
    Java知识总结-10
    Java知识总结-9
    Java知识总结-8
    Java知识总结-7
    SSO
  • 原文地址:https://www.cnblogs.com/zyb428/p/5283431.html
Copyright © 2011-2022 走看看