懒加载是什么就不多介绍了
OC 里面是怎么写懒加载的呢?
假设我有一个 nameLabel 属性
- (UILabel *)nameLabel {
if (!_nameLabel) {
_nameLabel = [UILabel new];
// ......自定义代码
}
return _nameLabel;
}
问题
还行还行,很简单的写法
但是,如果一个类里面充满了大量的属性,并且都想写成懒加载,在我看来有很多碍眼的代码,而且还得自己浪费精力写
if () {}
-
! _
(感叹号、下划线,要两个手指打🐶) return
干了多年的 iOS,如今我才真正的开始写大量的原生代码,开始体验到了懒加载的美妙,不过懒加载的代码实在让我眼睛痛。
所以经过提取公共代码的方式,我抽出了一个简便的... (方法?啪!想什么呢?不可能抽出硬编码方法的😠) ... 只能使用宏定义来简化懒加载的写法,本质和原来一模一样😂
LazyLoad 1.0
#define GGLazyLoad(Type, Name, Code) \
- (Type)Name { \
if (!_##Name) { \
Code; \
}\
return _##Name; \
}
#define GGLazyLoadNew(TypeNoPoint, Name, Code) \
- (TypeNoPoint *)Name { \
if (!_##Name) { \
_##Name = [TypeNoPoint new]; \
Code; \
}\
return _##Name; \
}
刚开始呢,我其实只用了 GGLazyLoad
这个宏,但后来发现很多对象创建也不过就是执行 new
方法而已,所以又定义了一个 GGLazyLoadNew
宏,把 new
操作省了,顺带连指针符号(*)都省得写了,太棒了。
但是在使用过程中,我遇到了令人头疼的问题,宏的代码块里面,不能写静态的数组、字典等内容。
LazyLoad 2.0
直到我看到 FDTemplateLayoutCell 的源码,看到 FDIndexPathHeightCache 里面有这么一个宏 FDPrimaryCall(...)
好奇心使我尝试了一下,神奇的发现它竟然可以在代码块里面写数组,于是研究了下,终于可以愉快的让所有懒加载都用上这个方便的宏了,实在是太感动了,感谢 Sunny 大神啊 👏
先来看看对比效果
我承认我夸大了,实际的代码中肯定会有大量的换行,两边的实际代码量,不会有这样两倍的差距。
阿勒,被你们发现了,改进的宏不止加入了数组字典的支持,还加入了一个简短的临时变量 z
, 可以让代码更简洁。不过按个人喜好,想用下划线变量也是可以的。
LazyLoad 最终版 !!!
#define GGLazyLoad(TypeNoPoint, Name, Code...) \
- (TypeNoPoint *)Name { \
if (!_##Name) { \
TypeNoPoint *z = nil; \
Code; \
_##Name = z; \
}\
return _##Name; \
}
#define GGLazyLoadNew(TypeNoPoint, Name, Code...) \
- (TypeNoPoint *)Name { \
if (!_##Name) { \
TypeNoPoint *z = [TypeNoPoint new]; \
Code; \
_##Name = z; \
}\
return _##Name; \
}
问题
当然了,这个宏定义并不是完美的,它有些无法解决问题
- 代码块里面的代码,着色不够完美
-
show document items
(ctrl+6)这个列表里面,无法显示懒加载方法 - 还有无法断点调试
还有的问题,比如宏用多了影响编译速度啊,我觉得不太大,文件编译后都会有缓存。
最后,都 2020 年了,还在这里折腾 OC 是不是太落后了 😂 。
// Swift
lazy var nameLabel: UILabel = {
let z = UILabel.init()
return z
}()