iOS生命周期相关

App生命周期

App程序的入口函数为main函数,找到由xcode自动生成的main.m文件:

#import 
#import "AppDelegate.h"

int main(int argc, char * argv[]) {
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

main函数作为整个程序的入口,内部只执行了一个方法:

int UIApplicationMain(int argc, char * _Nullable *argv, NSString *principalClassName, NSString *delegateClassName);

苹果官方给出的定义是:Creates the application object and the application delegate and sets up the event cycle.

即是创建了一个UIApplication对象以及一个application的代理,同时在代理中设置对了application各种事件循环的监听处理。

这个方法有4个参数:

  • argc:参数个数,对应main函数的入口参数
  • argv:参数内容,对应main函数的入口参数
  • principalClassName:代表UIApplication或其子类的名字,如果指定为nil,会为你假定一个
  • delegateClassName:代表代理的类名,一般都为AppDelegate(Xcode为你自动创建的代理类),负责监听应用生命周期的各个事件,当引发某个事件后调用代理中对应的方法

无返回值,因为该方法内部是一个消息循环,相当于死循环,只能用户手动关闭程序切断这个循环。

那么简单明了的就是我们的应用是通过AppDelegate与外部进行交互的。现在切到AppDelegate.m

AppDelegate类遵循了协议UIApplicationDelegate,里面定义了各个生命周期对应的调用方法,以下罗列出常用的一些

#import "AppDelegate.h"
//UIApplicationDelegate写在了AppDelegate.h文件中

@interface AppDelegate ()

@end

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    NSLog(@"Tells the delegate that the launch process is almost done and the app is almost ready to run");
    return YES;
}

- (void)applicationWillResignActive:(UIApplication *)application {
    NSLog(@"Tells the delegate that the app is about to become inactive");
}

- (void)applicationDidEnterBackground:(UIApplication *)application {
    NSLog(@"Tells the delegate that the app is now in the background");
}

- (void)applicationWillEnterForeground:(UIApplication *)application {
    NSLog(@"Tells the delegate that the app is about to enter the foreground");
}

- (void)applicationDidBecomeActive:(UIApplication *)application {
    NSLog(@"Tells the delegate that the app has become active");
}

- (void)applicationWillTerminate:(UIApplication *)application {
    NSLog(@"Tells the delegate when the app is about to terminate");
}

@end

简而言之,程序的运行如下:

  1. Initializing the App 程序启动:

    didFinishLaunchingWithOptions 程序以及启动 -> didBecomeActive 程序获得焦点

  2. Responding to App Life-Cycle Eveents 响应App生命周期事件:

    包括进入前后台,获取丢失焦点,程序即将关闭等。

常用的一些用户操作比如:

home键:程序失去焦点 -> 程序进入后台

打开程序:程序进入前台 -> 程序获得焦点

上拉或下拉中心:程序将要失去焦点,收回的时候获得焦点

来电:程序将要失去焦点,断开电话程序获得焦点

关闭应用:程序将要失去焦点 -> 程序进入后台 -> 程序将要终止

以上为App的生命周期,期间最重要的交互代码都写在AppDelegate代理中,所以一般大项目的AppDelegate内容都会十分多,所以我们需要通过分类的方式来解耦,不同业务对应不同的分类,这样会使项目代码更加清晰,比如Notifications 通知类,ConfigureSDK sdk注册类等等。

UIViewController的生命周期

现在讲视角移到更接近我们的控制器UIViewController上面来,我们平常接触最多最深的,也是bug、error最容易犯的地方来。

根据苹果文档,先简记以下UIViewController的整个过程:

#import "DemoViewController.h"

@interface DemoViewController ()
  
@end
  
@implement DemoViewController
 
//Creating a ViewController  
- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    /*creating a view controller
        返回一个新创建的viewcontroller,同时为其绑定(如果有的话)nib文件在指定的bundle上。
        发生在nib加载之前,此方法不是从nib创建控制器
  */
  self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    return self;
}

- (instancetype)init {
  self = [super init];
  return self;
}

- (instancetype)initWithCoder:(NSCoder *)aDecoder {
  //发生在nib加载期间,从nib加载控制器的时候使用此方法
  self = [super initWithCoder:aDecoder];
  return self;
}

-(void)awakeFromNib{
    [super awakeFromNib];
}

//Managing the View
- (void)loadView {
  /*creates the view that the controller manages
        创建一个controller管理的视图
  */
  [super loadView];
}

- (void)viewDidLoad {
  /*called after the controller's view is loaded into memory
        当控制器的视图被加载到内存中后调用该生命周期方法,也是xcode代码会自动帮我们生成的一个基本的生命周期响应方法
  */
  [super viewDidLoad];
}

//Responding to View-Related Events 接下来都是一些关于视图的控制器生命周期方法,中间过程有关于视图的布局行为
- (void)viewWillAppear:(BOOL)animated {
  //通知控制器,视图将要被加入视图层级中
  [super viewWillAppear:animated];
}

- (void)viewDidAppear:(BOOL)animated {
  //已经加入视图层级
  [super viewDidAppear:animated];
}

- (void)viewWillLayoutSubviews {
  //通知控制器即将对子视图进行布局
  [super viewWillLayoutSubviews];
}

-(void)viewDidLayoutSubviews{
  [super viewDidLayoutSubviews];
}

- (void)viewWillDisappear:(BOOL)animated {
  //将要从视图层级中移除
  [super viewWillDisappear:animated];
}

- (void)viewDidDisappear:(BOOL)animated {
  //已经从视图层级中移除
  [super viewDidDisappear:animated];
}

-(void)dealloc{
  //析构
}


UIViewController的初始化过程

我们创建控制器有俩种方法,即为上述前2种,第二种init方法默认实现了第一种,其中nibName和bundleName都传的nil。

DemoViewController *viewController = [[DemoViewController alloc] init];

这时候有区分了,如果我们是通过xib加载的则是上述过程,如果是通过storyboard加载的则是以下:

-[DemoViewController initWithCoder:]
-[DemoViewController awakeFromNib]
-[DemoViewController loadView]
-[DemoViewController viewDidLoad]

loadView:系统会自动帮我们创建的视图控制器创建一个空的view,所以一般情况下我们不会去自己调用这个方法,当我们需要在创建控制器视图的时期自定义一些东西或者做一些事情时可以手动调用。loadView的调用发生在当我们访问view的时候,每次访问时会调用self.view的get方法,在该get方法中会对self.view == nil 进行判断,如果为nil则会调用loadView方法,如果不为nil则返回当前view。(所以loadView方法可以被多次调用,只要访问self.view且其为nil的情况下)。

接下来是视图层级有关的调用方法:

viewXXAppear、viewXXDisappear。只要视图层级发生变化,比如push、present操作改变了视图层次,就会调用对应的方法。

这里面有一些小细节:

  1. 像Alert这样的控制器直接显示在最上层的,也是present需要调用吗:不需要,alert是在另一个window上,并没有改变本身控制器所在的window的视图层次。

  2. 锁屏、进入后台也不会触发,原因如上。

  3. 引用原文

    Note

    If a view controller is presented by a view controller inside of a popover, this method is not invoked on the presenting view controller after the presented controller is dismissed.

    比如当添加childViewController的时候,当移除子控制器时并不会调用这些方法。

关于子视图布局调用的2个方法,要注意的是子视图的尺寸大小在willLayout中是空的,没有设置好,这里经常会报错。在DidLayout中才被设置好,这里可以正确获取子视图大小。

你可能感兴趣的:(iOS生命周期相关)