在UI中,使用懒加载,也就是延迟加载来加载数据的时候,总是会面临几个问题?
如:1. >为什么先创建NSArray属性?
2. >为什么重写NSArray的get方法?
3.>为什么要判断是否为空?
4.>为什么下方代码"//1"这里不用NSString stringWithFormat: 而"//2"这里要使用?
5.>同时"//2"这里为什么使用的是%ld 来作为占位符?
这些问题不搞懂,懒加载就很难通透, 代码如下:
1 #import "ViewController.h" 2 3 @interface ViewController () 4 //先创建一个属性 (因为需要加载由字典组成的这个数组(也就是plist文件),所以需要先定义数组属性来接收和表示,) 5 @property (nonatomic, strong) NSArray *pictures; 6 @end 7 8 @implementation ViewController 9 10 //.重写pictures属性的get方法, 在该属性的get方法中读取images.plist文件中的数据, 并将数据设置给pictures属性 11 // 这种加载数据的方式就叫做"懒加载" 12 - (NSArray *)pictures { 13 if (_pictures == nil) { 14 // 读取plist文件并加载数据 15 // 1. 获取images.plist文件的完整的路径 16 NSString *path = [[NSBundle mainBundle] pathForResource:@"images.plist" ofType:nil]; 17 // 2. 根据plist文件的路径, 加载plist文件,再赋值给数组 18 _pictures = [NSArray arrayWithContentsOfFile:path]; 19 } 20 return _pictures; 21 } 22 @end 23 24 // 封装一个修改界面控件数据的方法 25 - (void)loadData { 26 // 2. 取出当前self.pictures中的对应的数据 27 NSDictionary *dict = self.pictures[self.index]; 28 29 // 3. 把数据设置到界面中对应的控件上 30 self.lblTitle.text = dict[@"desc"]; // 1 31 self.imgViewIcon.image = [UIImage imageNamed:dict[@"icon"]]; 32 self.lblIndex.text = [NSString stringWithFormat:@"%d / %ld", self.index + 1, self.pictures.count]; //2 33 34 35 // 设置"上一张"按钮 和 "下一张" 按钮的状态 36 self.btnPrevious.enabled = (self.index <= 0) ? NO : YES; 37 self.btnNext.enabled = (self.index >= self.pictures.count - 1) ? NO : YES; 38 }
原因及bug解析:
1.>为什么先创建NSArray属性?
因为需要加载由字典组成的这个数组(也就是plist文件),所以需要先定义数组属性来接收和表示,
2. >为什么重写NSArray的get方法?
因为在程序运行的时候,当需要读取这个数组的数据时,此时NSArray这个数组里面是空的,空的数组是没法满足我们的需求的,所以,我们这里就拦截这个get方法,重写它,将需要的数据加载进去,这样下面运行的时候,就会有我们需要的数据了
3.>为什么要判断是否为空?
因为程序运行时,第一次访问为空,而第二次访问就已经加载了,不为空了,所以需要判断 if (_pictures == nil),这样就避免了重复加载数据
4.>易错点bug: 为什么代码"//1"这里不用NSString stringWithFormat: 而"//2"这里要使用?
解析:
NSDictionary *dict=self.picture[self.index];
self.jieshaoLabel.text=dict[@"desc"];
第一种解释:这里使用的就是里面的属性, 所以可以直接用,
//dict[@"desc"]==等效于[NSString stringWithFormat:@"%@",dict[@"desc"]];
第二种解释: 因为这里直接就可以引用字典中的键值对的数据了,而下面的self.suoyinLabel.text需要拼接组合数据,需要通过调用其他的属性来组成,所以需要用;
5.>"//2"这里为什么使用的是%ld 来作为占位符?
@"%ld” ,self.picture.count;
这里是很多人都容易忽视的,所以也比较容易出现错误,
解析:
首先我们来看看count这个属性的底层实现:
@property (readonly) NSUInteger count;
从这个底层我们可以看得出,count是一个NSUInteger类型的,
而NSUInteger的底层又是什么呢? 我们来看看:如下:
#if __LP64__ || (TARGET_OS_EMBEDDED && !TARGET_OS_IPHONE) || TARGET_OS_WIN32 || NS_BUILD_32_LIKE_64
typedef long NSInteger;
typedef unsigned long NSUInteger;
#else
typedef int NSInteger;
typedef unsigned int NSUInteger;
#endif
可以看出,NSUInteger就是一个别名,而且是两种情况,
那就是如果你的设备是32位的,那么这个NSUInteger表示的就是给unsigned long取的一个别名,
那就是如果你的设备是64位的,那么这个NSUInteger表示的就是给 long取的一个别名,
所以,在使用过程中,我们首先要确定的就是当前编译器环境是处于32位,还是64位环境中,只有确定了这一步,这个bug才能避免!