开源项目 FDTemplateLayoutCell研究

本文详细介绍了iOS泛型的概念及其在实际编程中的应用,包括如何使用泛型类、逆变和协变特性。同时,展示了如何通过自定义宏实现更灵活的代码组织与复用。此外,还探讨了缓存机制在UITableView中的实现,以及如何通过宏技巧优化打印日志等常见场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

iOS泛型

可以指定容器中的对象类型,没有用任何的iOS runtime,纯编译器层面语法支持(llvm7.0,Xcode7以上),因此写好的程序可以在更低版本的iOS版本上愉快地跑起来。

NSArray<NSString *> *strings = @[@"sun", @"yuan"];
NSDictionary<NSString *, NSNumber *> *mapping = @{@"a": @1, @"b": @2};

编译器支持的很好,代码提示也可以出来。strings[0].length毫无压力,编译通过。

定义一个泛型类

@interface Stack2<ObjectType> : NSObject

- (void) push:(ObjectType)object;

@end

@implementation Stack2

- (void) push:(id)object
{
    NSLog(@"Stack2!");
}

不指定泛型的类型可以可以和任意泛型类型转化,但是不同类型的泛型不可以强转。如Stack2< NSString*> 和 Stack2< NSMutableString*>

因此,就有了逆变和协变这个概念:

__covariant :子类型指针可以向父类型指针转换(有用,子类转基类)

__contravariant:父类型指针可以向子类型转换

但是更多地是使用 __kindof 修饰符,一个基类簇。UITableViewCell就是一个适用的例子。

define进阶技巧

define 参数加#,表示将数转成字符串,也就是加一对双引号 
#define test1(a) NSLog(@#a);
test1(frankpcl);
结果就是 NSLog(@"frankpcl")

define 参数加##,表示将参数和其他字符粘合起来
#define test1(a) NSLog(@"%@",make_##a);
NSString* make_frankpcl = @"pcl";
test1(frankpcl);
结果是 NSLog(@"%@",make_frankpcl)

define可变参数,__VA_ARGS__
#define test1(a,...) NSLog(@#__VA_ARGS__);
test1(aa,bb;cc,dd);
相当于 NSLog(@"bb;cc,dd")

##还有一个用处,当可变参数为空时,多出来的一个逗号可能会导致编译错误,
#define test1(a,...) NSLog(@"aa",__VA_ARGS__);
test1(aa);
会编译错误,因为最后转成 NSLog(@"aa",)
改成#define test1(a,...) NSLog(@"aa",##__VA_ARGS__);
会去掉多余的,从而编译成功

核心思想

cache,通过扩展的category UITableView (FDIndexPathHeightCache) 在heightForCell的时候,向用户要求cell的布局,计算出高度,并缓存,下次用户请求时,直接返回缓存值

细节

  1. 既然有缓存就有清除机制,使用了一个category UITableView (FDIndexPathHeightCacheInvalidation) ,在+load方法调用时method swizzle了如下方法

     SEL selectors[] = {
            @selector(reloadData),
            @selector(insertSections:withRowAnimation:),
            @selector(deleteSections:withRowAnimation:),
            @selector(reloadSections:withRowAnimation:),
            @selector(moveSection:toSection:),
            @selector(insertRowsAtIndexPaths:withRowAnimation:),
            @selector(deleteRowsAtIndexPaths:withRowAnimation:),
            @selector(reloadRowsAtIndexPaths:withRowAnimation:),
            @selector(moveRowAtIndexPath:toIndexPath:)
        };

    在这些实现中都需要全部或者部分的清空高度缓存

  2. 当device方向转动时,并没有清空缓存,而是用了两个列表的缓存分别表示横向和纵向的高度。

  3. 自动布局时,核心高度计算

    fittingSize = [templateLayoutCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];

    手动布局时,需要用户实现下面函数来告知

    - (CGSize)sizeThatFits:(CGSize)size 
  4. cache用联合存储方式来保存

    objc_setAssociatedObject(self, _cmd, cache, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值