UIViewController Lifecycle

作者: Saxon_Geoffrey | 来源:发表于2015-03-24 00:07 被阅读743次

    作为每个初学者99.9%会接触到的UIViewController,这篇文章主要来讲讲UIViewController的生命周期。

    我们从一个例子来证明这个结论:

    如下是storyBoard的配置:

    ViewController.m

    @interface ViewController ()
    @property (nonatomic,strong)NSString *str;
    @property (weak, nonatomic) IBOutlet UIButton *button;
    @end
    

    下面是生命周期有关的方法:

    - (instancetype)initWithCoder:(NSCoder *)coder
    {
        self = [super initWithCoder:coder];
        if (self) {
            NSLog(@"0");
        }
        return self;
    }
    
    -(void)awakeFromNib{
        NSLog(@"1");
    }
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        NSLog(@"2");
    }
    
    -(void)viewWillAppear:(BOOL)animated{
        [super viewWillAppear:animated];
        NSLog(@"3");
    }
    
    -(void)viewWillLayoutSubviews{
        NSLog(@"4");
    }
    
    -(void)viewDidLayoutSubviews{
        NSLog(@"5");
    }
    
    -(void)viewDidAppear:(BOOL)animated{
        [super viewDidAppear:animated];
        NSLog(@"6");
    }
    
    -(void)viewWillDisappear:(BOOL)animated{
        [super viewWillDisappear:animated];
        NSLog(@"7");
    }
    
    -(void)viewDidDisappear:(BOOL)animated{
        [super viewDidDisappear:animated];
        NSLog(@"8");
    }
    
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
    }
    

    运行后点击按钮跳转到第二个控制器,打印如下:

    2015-03-24 00:00:44.771 test[2925:305854] 0
    2015-03-24 00:00:44.772 test[2925:305854] 1
    2015-03-24 00:00:44.778 test[2925:305854] 2
    2015-03-24 00:00:44.779 test[2925:305854] 3
    2015-03-24 00:00:44.785 test[2925:305854] 4
    2015-03-24 00:00:44.785 test[2925:305854] 5
    2015-03-24 00:00:44.788 test[2925:305854] 6
    2015-03-24 00:00:47.982 test[2925:305854] 7
    2015-03-24 00:00:47.987 test[2925:305854] 4
    2015-03-24 00:00:47.988 test[2925:305854] 5
    2015-03-24 00:00:48.489 test[2925:305854] 8
    

    也就是说,ViewController的生命周期基本是下面的步骤:

    Instantiated :初始化
    awakeFromNib:主要做一些viewDidLoad之前的事情
    outlets 的配置
    viewDidLoad
    viewWillLayoutSubviews和viewDidLayoutSubviews:
    viewWillAppear和viewDidAppear
    viewWillDisappear: and viewDidDisappear
    didReceiveMemoryWarning:收到内存警告
    现在不存在“unload”方法

    你可能会问为什么outlets 的配置介于awakeFromNib和viewDidLoad之间呢,我们可以通过下面的代码证实一下:

    -(void)awakeFromNib{
        NSLog(@"1");
        [_button setTitle:@"哈哈" forState:UIControlStateNormal];
    }
    

    运行结果发现按钮的标题并没有发生变化,我们再看:

    - (void)viewDidLoad {
        [super viewDidLoad];
        [_button setTitle:@"呵呵" forState:UIControlStateNormal];
        NSLog(@"2");
    }
    

    运行结果发现按钮的标题发生变化了,所以可以知道outlets 的配置是介于awakeFromNib和viewDidLoad,这点比较重要。

    1.initWithCoder ,
    关于initWithCoder ,你是不是觉得它更应该出现在数据持久化中呢?确实它是一个NSCoding protocol, 所以你在UIViewController的文档中不会找到它。initWithCoder 是一个类在IB中创建但在xocde中被实例化时被调用的。你可以理解为是一个解固过程,所以在这个时候view还没初始化,你可以完成一些需要在view未初始化之前调用的方法。注意这个方法在生命周期中只会调用一次。

    2.awakeFromNib
    当.nib文件或storyBoard文件被加载的时候,会发送一个awakeFromNib的消息到.nib文件或storyBoard文件中的每个对象,每个对象都可以定义自己的awakeFromNib函数来响应这个消息,执行一些必要的操作。也就是说通过nib文件创建view对象时执行awakeFromNib

    如果你不是从.nib文件或storyBoard文件中加载view,你可以在loadView方法通过代码初始化view。

    3.viewWillLayoutSubviews和viewDidLayoutSubviews

    viewWillAppear和viewDidAppear前会调用改方法,主要是和布局相关。在当几何方向改变时也会再次调用以下方法,例如旋转方向变化。
    (当选择方向改变还会收到 will/didRotateTo/From messages)

    再说下可能会看到的initWithNibName 和 loadNibNamed。
    主要是用于加载子view,使用此方法加载用户界面(xib文件)到我们的代码中,这样,可以通过操作这个加载进来的(xib)对象,来操作xib文件内容。 它们之间的区别是initWithNibName方法:是延迟加载,这个View上的控件是 nil 的,只有到 需要显示时,才会不是 nil 。
    loadNibNamed方法:即时加载,用该方法加载的xib对象中的各个元素都已经存在。

    - (void)submitShare:(id)sender
    {
        if (![self checkInputContentLegal]) {
            return;
        }
        [_textView resignFirstResponder];
        if (!_locationEnable) {//如果不显示地理位置
            _latitude = 0;
            _longtitude = 0;
            NSLog(@"不显示地理位置");
        }else{
            NSLog(@"显示地理位置,%f,%f",_latitude,_longtitude);
        }
        NSString *accseeToken = [AccountTool sharedAccountTool].account.accessToken;
        AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:kUploadURL]];
        manager.responseSerializer = [AFJSONResponseSerializer serializer];
        __weak typeof(self) weakSelf = self;
        NSString *encodeStatus = _textView.text;
        if (_images.count == 0) {
            [manager POST:@"2/statuses/update.json"
               parameters:@{@"access_token": accseeToken,
                                 @"status" : encodeStatus,
                                 @"visible" : @(_intVisible),
                                 @"lat" : @(_latitude),
                                 @"long" : @(_longtitude)}
                  success:^(NSURLSessionDataTask *task, id responseObject) {
                      NSLog(@"发送成功");
                      [self showSuccessHUD];
                      [self performSelector:@selector(back) withObject:self afterDelay:1.5];
                    }
                  failure:^(NSURLSessionDataTask *task, NSError *error) {
                      [self showFailHUD];
                      NSLog(@"发送失败");
                    }];
        }else{
            [manager POST:@"2/statuses/upload.json"
               parameters:@{@"access_token": accseeToken,
                               @"status" : encodeStatus,
                               @"visible" : @(_intVisible),
                               @"lat" : @(_latitude),
                               @"long" : @(_longtitude)}
                constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
                    NSMutableArray *images = [NSMutableArray arrayWithArray:weakSelf.images];
                    for (id asset in images) {
                        NSData *data = nil;
                        if ([asset isKindOfClass:[UIImage class]]) {
                            data = UIImageJPEGRepresentation(asset, 0.4);
                        }
                        if ([asset isKindOfClass:ALAsset.class]) {
                            UIImage *original = [UIImage imageWithCGImage: [[asset defaultRepresentation] fullScreenImage]];
                            data = UIImageJPEGRepresentation(original, 0.4);
                        }
                        [formData appendPartWithFileData:data name:@"pic" fileName:@"pic.jpg" mimeType:@"multipart/form-data"];
                        //新浪开放的API一次只能上传一张图片,选择多张的时候会使用最后一张,通过调用[http://open.weibo.com/wiki/2/statuses/upload_pic]() 接口生成高级接口statuses/upload_url_text中的参数pic_id,可以实习上传多张图片
                    }
                } success:^(NSURLSessionDataTask *task, id responseObject) {
                    NSLog(@"发送成功");
                    [self back];
                } failure:^(NSURLSessionDataTask *task, NSError *error) {
                    [self showFailHUD];
                }];
        }
    }
    

    相关文章

      网友评论

      • 小凡凡520:good mark
      • 我是卖报滴小行家:我改变它的subview的frame,没有触发5.viewWillLayoutSubviews,6.viewDidLayoutSubviews。
        - (void)viewDidAppear:(BOOL)animated {
        NSLog(@"6");
        self.aView.frame = CGRectMake(0, 0, 400, 200);
        }
        你看看我是不是哪里写错了
      • 07d93406ec39:你好。。我的順序是這樣的:
        1.view controller init
        2.awakeFromNib
        3.viewDidLoad
        4.viewWillAppear
        5.viewWillLayoutSubviews
        6.viewDidLayoutSubviews
        5.viewWillLayoutSubviews
        6.viewDidLayoutSubviews
        7.viewDidAppear
        8.viewWillDisappear
        5.viewWillLayoutSubviews
        6.viewDidLayoutSubviews
        9.viewDidDisappear

        可以發現5.6.重複了兩次,這是為什麼呢?Xcode Version 7.2 (7C68)
        Saxon_Geoffrey:@漩渦貓_Lanaya viewWillLayoutSubviews和viewDidLayoutSubviews 是当前控制器的view以及view中的subView的frame引起变化都会调用的一个方法。

      本文标题:UIViewController Lifecycle

      本文链接:https://www.haomeiwen.com/subject/avdgxttx.html