一、程序的生命周期

分析:
1.application:didFinishLaunchingWithOptions:
程序首次已经完成启动时执行,一般在这个函数里创建window对象,将程序内容通过window呈现给用户。
applicationWillResignActive(非活动)
程序将要失去Active状态时调用,比如有电话进来或者按下Home键,之后程序进入后台状态,对应的applicationWillEnterForeground(即将进入前台)方法。
该函数里面主要执行操作:
a . 暂停正在执行的任务
b. 禁止计时器
c. 减少OpenGL ES帧率
d. 若为游戏应暂停游戏
3.applicationDidEnterBackground(已经进入后台)
对应applicationDidBecomeActive(已经变成前台)
该方法用来:
a. 释放共享资源
b. 保存用户数据(写到硬盘)
c. 作废计时器
d. 保存足够的程序状态以便下次修复;
applicationWillEnterForeground(即将进入前台)
程序即将进入前台时调用,对应applicationWillResignActive(即将进入后台),
这个方法用来: 撤销applicationWillResignActive中做的改变。
applicationDidBecomeActive(已经进入前台)
程序已经变为Active(前台)时调用。对应applicationDidEnterBackground(已经进入后台)。
注意: 若程序之前在后台,在此方法内刷新用户界面
applicationWillTerminate
程序即将退出时调用。记得保存数据,如applicationDidEnterBackground方法一样。
二,UIViewController的生命周期

// 如果连接了串联图storyBoard 走这个方法
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
NSLog(@"%s", __FUNCTION__);
if (self = [super initWithCoder:aDecoder]) {
}
return self;
}
// xib 加载 完成
- (void)awakeFromNib {
[super awakeFromNib];
NSLog(@"%s", __FUNCTION__);
}
// 加载视图(默认从nib)
- (void)loadView {
NSLog(@"%s", __FUNCTION__);
self.view = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];
self.view.backgroundColor = [UIColor redColor];
}
//视图控制器中的视图加载完成,viewController自带的view加载完成
- (void)viewDidLoad {
NSLog(@"%s", __FUNCTION__);
[super viewDidLoad];
}
//视图将要出现
- (void)viewWillAppear:(BOOL)animated {
NSLog(@"%s", __FUNCTION__);
[super viewWillAppear:animated];
}
// view 即将布局其 Subviews
- (void)viewWillLayoutSubviews {
NSLog(@"%s", __FUNCTION__);
[super viewWillLayoutSubviews];
}
// view 已经布局其 Subviews
- (void)viewDidLayoutSubviews {
NSLog(@"%s", __FUNCTION__);
[super viewDidLayoutSubviews];
}
//视图已经出现
- (void)viewDidAppear:(BOOL)animated {
NSLog(@"%s", __FUNCTION__);
[super viewDidAppear:animated];
}
//视图将要消失
- (void)viewWillDisappear:(BOOL)animated {
NSLog(@"%s", __FUNCTION__);
[super viewWillDisappear:animated];
}
//视图已经消失
- (void)viewDidDisappear:(BOOL)animated {
NSLog(@"%s", __FUNCTION__);
[super viewDidDisappear:animated];
}
//出现内存警告 //模拟内存警告:点击模拟器->hardware-> Simulate Memory Warning
- (void)didReceiveMemoryWarning {
NSLog(@"%s", __FUNCTION__);
[super didReceiveMemoryWarning];
}
// 视图被销毁
- (void)dealloc {
NSLog(@"%s", __FUNCTION__);
}
三、OC中load方法和initialize方法的异同
对于OC中的类来说,在runtime中会有两个方法被调用:
- +load
- +initialize
这两个方法看起来都是在类初始的时候调用的,但其实还是有一些异同,从而可以用来做一些行为。
+load
首先,load方法是一定会在runtime中被调用的,只要类被添加到runtime中了,就会调用load方法,所以我们可以自己实现laod方法来在这个时候执行一些行为。
而且有意思的一点是,load方法不会覆盖。也就是说,如果子类实现了load方法,那么会先调用父类的load方法,然后又去执行子类的load方法。同样的,如果分类实现了load方法,也会先执行主类的load方法,然后又会去执行分类的load方法。所以父类的load会执行很多次,这一点需要注意。而且执行顺序是 类 -> 子类 ->分类。而不同类之间的顺序不一定。
+initialize
与load不同的是,initialize方法不一定会执行。只有当一个类第一次被发送消息的时候会执行,注意是第一次。什么叫发送消息呢,就是执行类的一些方法的时候。也就是说这个方法是懒加载,没有用到这个类就不会调用,可以节省系统资源。
还有一点截然相反,却更符合我们预期的就是,initialize方法会覆盖。也就是说如果子类实现了initialize方法,就不会执行父类的了,直接执行子类本身的。如果分类实现了initialize方法,也不会再执行主类的。所以initialize方法的执行覆盖顺序是 分类 -> 子类 ->类。且只会有一个initialize方法被执行。
Q1:load 方法是如何被调用的?
A1:当 Objective-C 运行时初始化的时候,会通过 dyld_register_image_state_change_handler 在每次有新的镜像加入运行时的时候,进行回调。执行 load_images 将所有包含 load 方法的文件加入列表 loadable_classes ,然后从这个列表中找到对应的 load 方法的实现,调用 load 方法。
load 可以说我们在日常开发中可以接触到的调用时间最靠前的方法,在主函数运行之前,load 方法就会调用。
由于它的调用不是惰性的,且其只会在程序调用期间调用一次,最最重要的是,如果在类与分类中都实现了 load 方法,它们都会被调用,不像其它的在分类中实现的方法会被覆盖,这就使 load 方法成为了方法调剂的绝佳时机。
但是由于 load 方法的运行时间过早,所以这里可能不是一个理想的环境,因为某些类可能需要在在其它类之前加载,但是这是我们无法保证的。不过在这个时间点,所有的 framework 都已经加载到了运行时中,所以调用 framework 中的方法都是安全的。
用途:1:可以新建类在该类中实现一些配置信息 2:runtime交换方法的时候,因为只需要交换一次方法,所有可以在该方法中实现交换方法的代码,用于只实现一次的代码 2:+ (void)initialize:当类被初始化的时候调用,可能会被调用多次,若是没有子类,则只会调用一次,若是有子类的话,该方法会被调用多次,若是子类的继承关系,先会调用父类的+ (void)initialize方法,然后再去调用子类的+ (void)initialize方法(若是继承关系,调用某个方法的时候,先会去父类中查找,若是父类中没有方法的实现就去子类中查找) 用途:1:在设置导航栏的全局背景的时候,只需要设置一次,可以重写该方法设置,最好是在该方法判断子类,若是自己,则实现设置全局导航栏的方法,若不是自己则跳过实现。2:在创建数据库代码的时候,可以在该方法中去创建,保证只初始化一次数据库实例,也可以用dispatch或是懒加载的方法中初始化数据库实例,也能保证只初始化一次数据库实例。其中也可以在+ (void)initialize方法中用dispatch也能保证即使有子类也只会初始化一次
网友评论