分类、扩展、KVO、KVC、通知、代理等
2020-05-20 本文已影响0人
Oh丶Really
分类(Category)
作用:
- 声明私有方法
- 分解体积庞大的类文件
- 把Framework的私有方法公开
特点:
- 运行时决议
- 可以为系统类添加分类
可以添加的内容:
- 实例方法
- 类方法
- 协议
- 属性
Category源码:
image加载调用栈:
image总结:
- 分类添加的方法可以“覆盖”原类方法
- 同名分类方法谁能生效取决于编译错误
- 名字相同的分类会引起编译错误
关联对象
能否给分类添加 “成员变量” ?
可以,但是是通过关联对象的方法添加;
添加的关联对象并没有被添加到原宿主类,而是存储在AssociationsHashMap中,由AssociationsManager管理;
所有对象的关联内容都在一个全局容器中;
id objc_getAssociatedObject(id objct, const void * key)
void objc_setAssociatedObject(id objct, const void* key,
id value, objc_AssociationPolic polic)
void objc_removeAssociatedObjects(id object)
image
扩展(Extension)
一般用扩展做什么
- 声明私有属性
- 声明私有方法
- 声明私有成员变量
扩展的特点
- 编译时决议
- 只以声明的形式存在,多数情况下寄生于宿主的.m中
- 不能为系统类添加扩展
代理(Delegate)
- 准确的说是一种软件设计模式
- iOS中以 @protocol 形式存在
- 传递方式一对一的形式
通知(NSNotification)
- 是使用观察者模式来实现的用于跨层传递消息的机制
- 传递方式一对多
如何实现通知机制?
imageObservers_list 是一个数组,用来存储观察者以及回调方法
KVO
- KVO 是 Key-value observing的缩写
- 是 Object-C 对观察者模式的一个实现
- Apple 使用了 isa 混写(isa-swizzling)来实现KVO
实现机制:
imageNSKVONotification_A的setter实现:
image通过KVC设置value能否生效?
可以生效
KVC会调用setter方法,又setter方法被重写,所以KVO可以生效
通过成员变量直接赋值value能否生效?
不会生效
可以手动KVO实现,在赋值前调用 willChangeValueForKey,赋值后调用didChangeValueForKey
总结:
- 使用 setter 方法改变值 KVO 才会生效
- 使用 setValue:forKey:改变值KVO才会生效
- 成员变量直接修改需要手动添加KVO才会生效
KVC
-
KVO 是 Key-value coding的缩写
-
valueForKey
调用流程
image
Accessor Method(存储器/访问器方法的判断): 1、实现了一个名为<getKey>的方法 2、<key>,有get方法名称,属性名称 3、实现<isKey>的get方法
Instance var实例变量 1、_key 2、_isKey 3、key 4、isKey
-
setValue: forKey:
调用流程
image
-
属性关键字
分类:
- 读写权限
- 原子性
- 引用计数
读写权限:
- readonly
- readwrite(默认属性)
原子性
- atomic(默认属性) 赋值和获取是线程安全的; 但是例如对数组操作,并非是atomic负责范围内,无法保证线程安全
- nonatomic
引用计数
- retain(mrc)/strong(arc)
- assign(基本数据类型、对象类型)/unsafe_unretained(mrc)
- weak
- copy
assign:
- 修饰基本数据类型,如int、BOOL等
- 修饰对象类型时,不改变其引用计数。
- 会产生悬垂指针(修饰的对象被释放时,assign的指针仍指向原对象的内存地址,此时通过此指针访问可能引起内存泄露)
weak:
- 不改变被修饰对象的引用计数
- 所指对象在被释放之后会自动置未nil
copy:
- 浅拷贝就是对内存地址的复制,让目标对象指针和源对象指向同一片内存空间
浅拷贝:
* 会使被拷贝对象的引用计数加一
* 不会重新分配新的内存
- 深拷贝让目标对象指针和源对象指针指向两片内容相同的内存空间
浅拷贝:
* 不会使被拷贝对象的引用计数变化
* 会重新分配新的内存
image
总结:
- 可变的copy和mutableCopy都是深拷贝
- 不可变对象的copy是浅拷贝,mutableCopy是深拷贝
- copy对象返回的都是不可变对象
练习
1、MRC下如何重写retain修饰变量的setter方法
@property (nonatomic, retain) id obj;
- (void)setObj:(id)obj{
if (_obj != obj){
[_obj release];
_obj = [obj retain];
}
}
2、简述分类的实现原理
* 由运行时决议的
* 不同分类中含有的同名分类方法最终生效取决于编译时谁最后参与编译
* 分类方法会覆盖同名的宿主方法
3、KVO的实现原理
4、为分类添加成员变量