分类
分类的作用
分解体积庞大的类文件
为系统类添加方法
声明私有方法
把Framework的私有方法公开
分类添加过程
在程序运行时候,runtime会把分类的实例方法等信息合并到类对象的实例方法列表中,会把分类的类方法合并到元类对象的类方法列表中(在原方法之前)。
以添加实例方法为例:
运行时候,会遍历分类列表,拿到每一个分类的实例方法列表
分类能添加成员变量吗?
不能。只能通过关联对象(objc_setAssociatedObject)来模拟实现成员变量,但其实质是关联内容,所有对象的关联内容都放在同一个全局容器哈希表中:AssociationsHashMap,由AssociationsManager统一管理。
#关联对象: 使用objc_setAssociatedObject函数可以给某个对象关联其他的对象。
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
#获取关联的对象: 使用objc_getAssociatedObject函数可以通过键来取出某个对象的关联对象。
id objc_getAssociatedObject(id object, const void *key)
#移除关联的对象:使用objc_removeAssociatedObjects函数可以移除某个对象身上的所有关联的对象。
void objc_removeAssociatedObjects(id object)
〜
〜
〜
扩展
一般用扩展做什么?
声明私有属性,声明方法(没什么意义),声明私有成员变量
扩展的特点
编译时决议,只能以声明的形式存在,多数情况下寄生在宿主类的.m中,不能为系统类添加扩展。
分类跟扩展的区别
扩展:在编写完分类文件后,直接把分类内容添加到相关的宿主类上。
分类:是在运行时使用runtime把分类的内容添加到宿主类上。
〜
〜
〜
代理
代理是一种设计模式,以@protocol形式体现。
一般是一对一传递,一般以weak关键词以规避循环引用。
本质是获得对象,调用方法返回数据。
〜
〜
〜
通知
使用观察者模式来实现的用于跨层传递信息的机制。
传递方式是一对多的。
原理是在通知中心维护一个map表,key为通知的名称,value为observer。本质为持有对象,所以在不用时,需要释放对象。
〜
〜
〜
KVO
使用观察者设计模式,使用isa混写技术。
当A类实例被KVO监听时,Runtime会转建一个继承自A类的新类NSKVONotifying_A,并重写被观察属性的setter和getter方法。如果代码中有创建NSKVONotifying_A类,注册A类KVO时会崩溃。
何时触发:
使用setter方法改变值时,会触发KVO;
使用KVC setValue:forKey:改变值时,会触发KVO;
成员变量直接修改,不会触发KVO,需手动添加willChangeValueForKey和didChangeValueForKey方法才会触发;
- (void)setName:(NSString *)newName {
[self willChangeValueForKey:@"name"]; //KVO 在调用存取方法之前总调用
[super setValue:newName forKey:@"name"]; //调用父类的存取方法
[self didChangeValueForKey:@"name"]; //KVO 在调用存取方法之后总调用
}
~
~
~
KVC
KVC的全称是Key-Value Coding,俗称“键值编码”,可以通过一个key来访问某个属性。KVC的操作方法由NSKeyValueCoding提供,而他是NSObject的类别,也就是说ObjC中几乎所有的对象都支持KVC操作。
常用方法
获取值的方法
valueForKey:,传入NSString属性的名字。
valueForKeyPath:,传入NSString属性的路径,xx.xx形式。
valueForUndefinedKey它的默认实现是抛出异常,可以重写这个函数做错误处理。
修改值的方法
setValue:forKey:
setValue:forKeyPath:
setValue:forUndefinedKey:
setValue:forKey的搜索过程:
- 首先搜索set<Key>:方法
如果成员用@property,@synthsize处理,因为@synthsize告诉编译器自动生成set<Key>:格式的setter方法,所以这种情况下会直接搜索到。
注意:这里的<Key>是指成员名,而且首字母大写。 - 上面的setter方法没有找到,如果类方法accessInstanceVariablesDirectly返回YES(注:这是NSKeyValueCodingCatogery中实现的类方法,默认实现为返回YES)。
那么按_<key>,_is<Key>,<key>,is<key>的顺序搜索成员名。 - 如果还是没有找到设置成员的值,就会调用setValue:forUndefinedKey:。
- 如果没有重写setValue:forUndefinedKey程序会马上崩溃。
〜
〜
〜
属性关键字
1.读写权限:readonly,readwrite(默认)
2.原子性: atomic(默认),nonatomic。atomic读写线程安全,但效率低,而且不是绝对的安全,比如如果修饰的是数组,那么对数组的读写是安全的,但如果是操作数组进行添加移除其中对象的还,就不保证安全了。
3.引用计数:
retain/strong:引用计数加1
assign:修饰基本数据类型,修饰对象类型时,不改变其引用计数,会产生悬垂指针,修饰的对象在被释放后,assign指针仍然指向原对象内存地址,如果使用assign指针继续访问原对象的话,就可能会导致内存泄漏或程序异常
weak:不改变被修饰对象的引用计数,所指对象在被释放后,weak指针会自动置为nil
copy:分为深拷贝和浅拷贝
浅拷贝:对内存地址的复制,让目标对象指针和原对象指向同一片内存空间会增加引用计数
深拷贝:对对象内容的复制,开辟新的内存空间
可变对象的copy和mutableCopy都是深拷贝
不可变对象的copy是浅拷贝,mutableCopy是深拷贝
copy方法返回的都是不可变对象
@property (nonatomic, copy) NSMutableArray * array;这样写有什么影响?
因为copy方法返回的都是不可变对象,所以array对象实际上是不可变的,如果对其进行可变操作如添加移除对象,则会造成程序crash。
〜
〜
〜
参考:Objective_C语言特性:分类、扩展
参考: iOS开发-OC篇-KVC详解