「OC」视图控制器的懒加载策略
懒加载
懒加载(Lazy Loading)是一种设计模式,其核心思想是在需要时才进行对象的创建或资源的加载,而不是在对象初始化时立即完成。这种技术可以提高程序的性能和效率,减少资源的消耗。懒加载特别适用于那些创建代价高、内存占用大或者初始化过程复杂的对象。
懒加载的优点
- 性能提升:通过推迟对象的创建,减少了程序启动时的资源消耗和初始化时间。
- 内存优化:对象的创建和资源的加载在实际需要时才进行,有效节省了内存。
- 提高响应速度:初始化时不需要加载所有资源,使得程序在启动和运行时更加响应迅速。
- 降低复杂度:只在需要的时候才创建和初始化对象,有助于降低系统的复杂度。
注意:如果使用懒加载的话则一定要注意进行判空,如果为空那么再去进行实例化。
常见的懒加载实现方法
在 Objective-C 中,懒加载通常是通过重写 getter
方法来实现的。以下是一个示例:
#import "ViewController.h"
@interface ViewController ()
@property (strong, nonatomic) UILabel *label;
@end
@implementation ViewController
- (UILabel*) label {
if (!_label) {
_label = [[UILabel alloc]init];
_label.font = [UIFont systemFontOfSize:45];
_label.text = @"LazyLoad";
_label.frame = CGRectMake(120, 400, 260, 50);
_label.textColor = [UIColor blackColor];
}
return _label;
}
- (void) touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[self label];
//点击后将label添加到视图
[self.view addSubview:self.label];
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
@end
得到的内容如下,当我们点击屏幕懒加载的UILabel才会显示在屏幕之上
一般来说,对于需要直接加载在页面上的内容,我们不使用懒加载,直接进行普通加载即可,而那些不出现在首页需要点击才弹出的页面,才使用懒加载,可以有效缩短加载的时间
在重写getter方法的过程之中,我们只能用直接访问属性的方法进行方法(即_加上属性名),如果使用间接访问属性的方法,使用getter方法很可能引起循环引用
使用懒加载的注意事项
- 线程安全:在多线程环境中,确保懒加载实现是线程安全的。通常需要使用同步机制(如锁)来防止并发访问导致的问题。
- 性能考虑:虽然懒加载可以减少初始化开销,但也要确保在实际需要时加载的操作不会过于耗时,否则可能会影响用户体验。
- 内存管理:确保对象在不再需要时能够被正确释放,以避免内存泄漏。
控制器的懒加载
通过我们前面对懒加载的了解,我们现在可以在编译器进行实验
SceneDelegate.h
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
self.window.frame = [UIScreen mainScreen].bounds;
ViewController *vc = [[ViewController alloc] init];
NSLog(@"%s",__func__);
vc.view.backgroundColor = [UIColor redColor];
self.window.rootViewController = vc;
[self.window makeKeyAndVisible];
}
ViewController.h
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"%s",__func__);
self.view.backgroundColor = [UIColor orangeColor];
}
我们最后得到的控制器,是一个红色背景的控
制器,似乎好像没有问题,因为我们先创建控制器,在里面对背景颜色赋值,再在SceneDelegate.h
之中进行重新赋值。
不过我们可以来看看打印的内容
NSLog(@"%s",__func__);
的意思是用于在日志中打印当前函数的名称。看到打印的内容,我们先打印出来的是在- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions
的方法,那么在SceneDelegate.h
的赋值程序是先运行的,那么关于背景颜色的赋值和我们之前的猜想不同的。
那是怎么回事呢,我们再对程序进行打印,来印证我们的操作
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
self.window.frame = [UIScreen mainScreen].bounds;
ViewController *vc = [[ViewController alloc] init];
NSLog(@"%s",__func__);
NSLog(@"访问控制器属性之前");
vc.view.backgroundColor = [UIColor redColor];
NSLog(@"访问控制器属性之后");
self.window.rootViewController = vc;
[self.window makeKeyAndVisible];
}
不难看到,只有当我们访问到控制器属性之后,才会开始运行[ViewController viewDidLoad]
这个方法,也就是说只有当访问了属性控制器的视图才会开始进行加载。
我们带着这个猜想,继续进行实验,我们可以使用isViewLoaded
检验控制器是否进行加载
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
self.window.frame = [UIScreen mainScreen].bounds;
ViewController *vc = [[ViewController alloc] init];
if ([vc isViewLoaded]) {
vc.view.backgroundColor = [UIColor redColor];
}
self.window.rootViewController = vc;
[self.window makeKeyAndVisible];
}
我们可以看到,控制器的背景反而变成了橙色,说明当我们创建了控制器,控制器并不会马上加载,而是我们将控制器作为UIWindow
的根视图时或者访问到了控制器的属性,控制器才会进行加载。通过以上示例,我们其实不难发现,懒加载这个方法是在iOS的开发之中随处可以领略到的一个思想