基础知识
- nonatomic
非原子属性,提高性能,但线程不安全
- atomic
原子属性,相对来说是线程安全,只是保证了setter和getter是线程安全,在异步函数中,也不是绝对安全,会降低性能
- strong
强引用,持有对象,引用计数 +1,相当于 MRC 环境中的 retain
- copy
强引用,持有对象,引用计数 +1
- weak & assign
weak 仅用于修饰对象,assign 也可以修饰对象,但多用于修饰基本数据类型
相同点:
weak 与 assign 都表示了一种"非拥有性关系",弱引用,不会影响引用计数
不同点:
被 weak 修饰的对象在销毁时会指向 nil
assign 修饰的对象则会造成野指针导致程序崩溃
- Block
block 3 种形态,
没有使用外部变量时,属于全局区域,
使用外部变量时,属于栈区域,栈区特点是内存随时会被系统回收,
导致 crash 崩溃,因此要用 copy 修饰,copy 到堆区域后,
不会函数执行完就销毁,会随着持有对象销毁而销毁
copy 返回一个不可变类型,不会随外界改变而改变
strong 有可能指向一个可变类型,会随外界改变而改变,故不能使用 strong 修饰
进阶知识
- UIView & CALayer
UIView 是用来显示内容的,可以处理用户事件
CALayer 是用来绘制内容的,对内容进行动画处理,依赖UIView来进行显示,不能处理用户事件
UIView 来自CALayer,高于CALayer,是CALayer高层实现与封装
- RunLoop
RunLoop 是 iOS 系统最核心的机制,APP应用启动后,会默认创建主线程的 RunLoop
1)保持程序的持续运行;
2)节省CPU资源,提高程序性能,该做事时做事,没事时休息;
3)处理App中的各种事件(如:触摸事件、定时器事件、Selector事件);
如何启用:调用 run 方法,启用子线程 RunLoop
线程常驻:调用 addPort 方法,使线程常驻
1)@autoreleasepool 是自动释放池,使我们更灵活的管理内存;
2)使用 @autoreleasepool { custom code } 创建自动释放池,随后自动释放内存;
3)官网中,一个自动释放池使用场景的例子
NSArray *urls = <# An array of file URLs #>;
for (NSURL *url in urls) {
@autoreleasepool {
NSError *error;
NSString *fileContents = [NSString stringWithContentsOfURL:url
encoding:NSUTF8StringEncoding error:&error];
/* Process the string, creating and autoreleasing more objects. */
}
}
- KVC
Key-Value-Coding(键值编码)
存值
1)当某个对象调用 【setValue:forKey】方法时
2)判断该对象有没有指定 Key 的 setter 方法,若存在,则直接调用 setter 方法进行赋值
3)若不存在,则按照 "_Key,_isKey,Key,isKey" 顺序依次查找,找到后直接对该属性进行赋值
4)如果都没有找到,则会执行【setValue: forUndefinedKey】方法,并抛出异常
取值
1)当某个对象调用 【valueForKey: 】方法时
2)判断该对象有没有指定 Key 的 getter 方法,若存在,则直接调用 getter 方法获取值
3)若不存在,则按照 "_Key,_isKey,Key,isKey" 顺序依次查找,找到后直接读取该属性值
4)如果都没有找到,则会执行【valueForUndefinedKey:】方法,并抛出异常
对于 NSDictionary
当调用 【setValue:forKey】时,相当于调用了 【setObject: forKey】
当值为 nil 时,则会调用【removeObject:ForKey】方法移除该键
- KVO
Key-Value-Observing(键值观察)
KVO 是基于 runtime 机制实现的
通过 setter 方法或KVC赋值,才可以触发KVO机制
直接修改成员变量值,不会触发KVO【例如 _name = @"newName" 】
添加KVO后,要在合适时机移除KVO
1)当对 Person 对象中的 name 属性进行监听观察时
2)系统会自动生成一个继承于 Person 名为 NSKVONotifying_Person 的子类
3)在子类的中,重写 setName方法
- ( void)setName:( NSString*)newName {
// 被观察属性值,改变之前调用
[ self willChangeValueForKey: @"name"];
// 调用父类的set方法
[ super setValue:newName forKey: @"name"];
// 被观察属性值,改变之后调用
[ self didChangeValueForKey: @"name"];
}
4)通过此方法,处理观察值发生改变的相关逻辑
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
5)手动触发 KVO
willChangeValueForKey
didChangeValueForKey
- Event
事件链,包括事件传递链和事件响应链,当用户触发一个事件时,
系统会将Event 打包加入到 UIApplication 消息队列中,
然后传递到 window 对象,通过 【hitTest: withEvent】和【pointInside: withEvent】方法,
判断当前操作是否在 window 窗口内,如果返回 true,则倒序遍历其子视图,
找到最终响应的目标 view,完成事件传递与响应
事件传递链
UIApplication -> UIWindow -> rootViewController -> subView -> targetView
事件响应链
targetView -> parentView -> rootViewController -> UIWindow -> UIApplication
网友评论