美文网首页A原理/底层
iOS控制器加载底层原理和UI初始化的过程

iOS控制器加载底层原理和UI初始化的过程

作者: 找不到工作的iOS | 来源:发表于2017-08-28 18:15 被阅读62次

    控制器加载底层原理

    1.有xib文件的控制器加载

    - 1. [init]
    - 2. [initWithNibName: bundle:]
    - 3. [viewDidLoad]
    - 4. [viewWillAppear:]
    - 5. [viewDidAppear:]
    
    • 可以看出init里面封装了initWithNibName
    • 如果bundle的参数为nil,则默认为[NSBundle mainBundle]
    • xib编译后会变为nib文件(包内容-资源文件)

    2.无xib文件的控制器加载

    - 1. [loadView] //有xib获取xib的view,没有自己生成
    - 2. [viewDidLoad]
    - 3. [viewWillAppear]
    - 4. [viewWillLayoutSubviews]
    - 5. [viewDidLayoutSubviews:]
    - 6. [viewDidAppear:]
    
    • 如果没有xib文件,就会通过loadView方法生成一个self.view
    • [loadView] (苹果建议不要直接调用此参数,其实可以无视)
    • 如果在[loadView]里面没有调用[super loadView];会进入一个死循环,实质是获取不到一个UIView的实例。
    • self.view实质是一个懒加载,伪代码实现如下
    - (UIView *)view {
          if(!_view) {
            [self loadView];
           //如果这里没有对self.view初始化,就会一直循环
            [self viewDidLoad];
          }
          return _view;
    }
    

    3.实战应用 - 拆分Controller

    • Controller主要是起到一些调度作用
    • 我们可以将一些业务逻辑转移到CustomView,可以采用block KVO结合实现
    • MVCS 设计模式就是基于loadView实现
    - (void)loadView {    
        //[super loadView]; //系统的
        self.view = [CustomView new]; //自己的 (给控制器自己定义的)    
    }
    

    4.探究xib文件屏幕尺寸设置在运行时的影响

      1. xib文件中选择7plus屏幕大小的尺寸414 x 716
      1. 选择7plus模拟器加载,在viewDidLoad打上断点po一下,结果view的frame = (0, 0, 320, 480);
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        self.view.backgroundColor = [UIColor blueColor];
        //断点处,po self.view
    }
    
      1. 我们可以得到结论在viewDidLoad中,self.view并没有成型。
      1. 所以我们在viewDidAppear或者viewWillLayout操作布局会比viewDidLoad安全

    UI初始化的过程

    1.无xib的UIView加载

    1.[init]
    2.[initWithFrame:]
    3.[layoutSubview] 
    

    2.有xib的UIView加载

    1.[initWithCoder]
    2.[awakeFromNib:]
    3.[layoutSubview] //只要addSubView都会执行
    

    3.运行时的布局成型时机之[layoutSubview]

    • 如果在initWithFrame做布局或者添加子视图的操作,可能会无法达到预期的效果,比如UIButton UILabel
    • 原因是在initWithFrame中视图并没有完全成型,最安全的做法实在layoutSubview中做布局操作
    • 子视图的初始化操作还是可以放在父视图的initWithFrame中的
    • 当我们在外部需要调用[layoutSubview]的时候,一般不用[self layoutSubview]而用[self setNeedsLayout]
      -[setDisplay]类似[layoutSubview],他调用的是[drawRect]
    • 多次调用[self setNeedsLayout]只会在当前runloop执行一次[layoutSubview]
    • [layoutIfNeeded]立刻刷新布局,获取准确的frame。可以结合[self setNeedsLayout]使用,立刻执行完[layoutSubview]的布局配置

    4.[layoutSubview]实战运用

    • 如果你已经明白3.中我表达的内容,那么我们在对button自带的title以及imageview的大小与位置不满意的时候,可以在自定义的button内的layoutSubview重写frame
    #import "CustomButton.h"
    
    @implementation CustomButton
    
    - (void)layoutSubviews {
        self.titleLabel.frame = CGRectMake(<#CGFloat x#>, <#CGFloat y#>, <#CGFloat width#>, <#CGFloat height#>);
        self.imageView.frame = CGRectMake(<#CGFloat x#>, <#CGFloat y#>, <#CGFloat width#>, <#CGFloat height#>);    
    }
    
    @end
    

    -[tableView reload]由于具有一定的延迟,如果我们要立刻获取某个cell的准确布局位置,那么可以

    [tableView reload];
    [self setNeedsLayout];
    [self layoutIfNeeded];
    

    5.[darwRect:]

    • 当系统主动调用到[darwRect:]的时候,首先内部会生成当前layer的上下文
    • 然后将这个上下文push到栈顶,系统默认处理top of stackcontext
    • 处理结束后移除此上下文
    • drawRect配合xib可以让控制可视化调整,注意的是只是修改的是layer层,比如添加一个subview是不会可视化的
    - (void)drawRect:(CGRect)rect {
       
    //系统底层的执行思想 
        CGContextRef contextRef; //获取当前CALayer的上下文,实际不能这样操作,只是一个示意
        UIGraphicsPushContext(contextRef); //push到top of stack
        UIGraphicsPopContext(); //从top of stack移除,并且把current context恢复为上一个context
        
    }
    

    6.视图可视化操作

    • 可视化属性 IB_DESIGNABLE
    #import <UIKit/UIKit.h>
    
    IB_DESIGNABLE
    
    @interface CustomView : UIView
    
    @end
    
    • 可视化参数
    #import <UIKit/UIKit.h>
    
    IB_DESIGNABLE
    
    @interface CustomView : UIView
    @property (nonatomic,strong)IBInspectable UIColor *strokeColor;
    @end
    
    #import "CustomView.h"
    
    @implementation CustomView
    
    - (void)drawRect:(CGRect)rect {
        [self.strokeColor setStroke];
    }
    
    @end
    
    • 此时xib中就有了strokeColor属性的设置选项


      strokeColor.png

    相关文章

      网友评论

        本文标题:iOS控制器加载底层原理和UI初始化的过程

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