控制器加载底层原理
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,可以采用blockKVO结合实现 -
MVCS设计模式就是基于loadView实现
- (void)loadView {
//[super loadView]; //系统的
self.view = [CustomView new]; //自己的 (给控制器自己定义的)
}
4.探究xib文件屏幕尺寸设置在运行时的影响
-
xib文件中选择7plus屏幕大小的尺寸414 x 716
-
- 选择
7plus模拟器加载,在viewDidLoad打上断点po一下,结果view的frame = (0, 0, 320, 480);
- 选择
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor blueColor];
//断点处,po self.view
}
- 我们可以得到结论在
viewDidLoad中,self.view并没有成型。
- 我们可以得到结论在
- 所以我们在
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做布局或者添加子视图的操作,可能会无法达到预期的效果,比如UIButtonUILabel - 原因是在
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 stack的context - 处理结束后移除此上下文
-
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









网友评论