一、控制器的初始化过程:
1、两种初始化方式: xib和纯代码。
2、
- (instancetype)init{}
-- 代码初始化方法
- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil{}
-- xib初始化方法
(1)init 方法中封装了 initWithNibName 方法;
(2)nibNameOrNil 如果为nil,默认去找类名相同的xib文件;nibBundleOrNil 如果为nil,默认去找 mainBundle。
也可以指定xib文件进行加载。
(3)所以我们在写一些初始化逻辑,尽量写在 initWithNibName 方法中。
二、控制器中的View 初始化过程:
- (void)loadView{}
(1)这个方法时控制器中的View 初始化方法,默认是执行的。
(2)控制器中的View(self.view)能不能指定呢??
在 loadView方法中重新给 self.view 赋值, 指定为我们自定义的View即可!(不要执行 [super loadView]!!!)
这样做的好处就是: 控制器和View分离,所谓C弱化。(MVCS 就是利用这种处理) 结合KVO, 在C中处理View中的业务~
(3)空实现此方法,并在viewDidLoad方法中执行self.view,会造成死循环!!!
因为 self.view 是一个懒加载过程。调用self.view 时,会执行loadView,此时返回为nil。又执行viewDidLoad -> self.view -> loadView -> viewDidLoad ...
(4)View 的初始化方式:
a. 纯代码布局:
- (instancetype)init{}
- (instancetype)initWithFrame:(CGRect)frame{}
view纯代码布局的初始化过程, init方法中封装了 initWithFrame, 尽量把初始化代码写在 initWithFrame 中。
b.xib布局:
- (instancetype)initWithCoder:(NSCoder *)aDecoder{}
- (void)awakeFromNib{}
xib文件布局view, 初始化方法执行 initWithCoder,然后执行 awakeFromNib
三、布局问题:
1、控制器:
- (void)viewWillLayoutSubviews{ }
在xib布局时,viewDidLoad viewWillAppear 中的self.view 大小都不是屏幕的大小,在 viewWillLayoutSubviews 方法中,才是真正屏幕大小。
可以把布局代码移动这个方法中,解决布局中的bug。
2、view:
- (void)layoutSubviews{}
这里去修改子控件的布局
setNeedsLayout
:会调用对象的 layoutSubviews 方法,但是不会立即执行,用runloop解释,就是在当前循环结束时,下一个循环去执行,暂时标记而已。这样做的好处是界面可以统一刷新,提高性能。
layoutIfNeeded
:会调用对象的 layoutSubviews 方法,并且立即执行。
setNeedsDisplay
:会调用对象的 drawRect 方法,也是不会立即执行,原理同setNeedsLayout相同。
四、drawRect 方法:
- (void)drawRect:(CGRect)rect {}
UIGraphicsPushContext(context2);
UIGraphicsPopContext();
1、stack 存放上下文的栈, 默认是没有的 push一个context存一个。正常不对这个栈进行操作。
2、上下文跟CALayer是有关系的,修改context会渲染到CALayer上去。
五、可视化
IB_DESIGNABLE:
IBInspectable:
开发中很少使用,知道就好。