OC语言特性
OC语言特性
前言
我们今天从iOS的分类
、关联对象
技术、扩展
、代理
、通知
、KVO
、KVC
实现机制和属性关键字
来学习下Objective-C语言的特性。
分类(Category)
- 我们用分类做了哪些事情呢
- 声明私有方法
- 分解体积庞大的类文件
- 把Framework的私有方法公开化
- 分类的
特点
:- 运行时决议:编译时,并未把分类的方法添加到宿主类中,而是在运行时,通过runtime技术添加到宿主类中
- 可以为系统类添加分类
- 那么分类中都可以添加哪些内容?
- 实例方法
- 类方法
- 协议
- 属性(只是声明了get、set方法,并没有生成实例变量)
- 从分类的源码的分析可以得出的结论:
- 分类添加的方法可以”覆盖”原来类的方法
- 多个分类的同名方法,最后参与编译的分类的方法会生效
- 名字相同的分类会引起编译报错
关联对象
- 场景:怎样为分类添加“成员变量”
- 可以添加成员变量
- 不能在分类的声明和实现的时候直接添加成员变量
- 可通过
关联对象
技术为分类添加
关联对象
技术的相关函数:- id objc_getAssociatedObject(id object, const void* key)
- void objc_setAssociatedObject(id object, const void* key, id value, objc_AssociationPolicy policy)
- objc_AssociationPolicy:关联策略,value是以什么方式(copy、retain、assign)关联到宿主对象上面
- void objc_removeAssociatedObjects(id object):移除所有的关联对象
- Q:使用关联对象技术添加的成员变量,添加到哪里了呢?
- 关联对象的本质:
- 关联对象是由系统提供的AssociationsManager管理,并在AssociationsHashMap存储的。
- 所有对象的关联内容都在
同一个全局容器
中。并且为不同分类添加的值都存放在同一个全局容器当中。
- 关联对象技术的
数据结构
- Q:怎样清除一个关联对象被关联的值呢?
- 调用setAssociatedObject方法,value传值nil即可;其方法内部会把关联的值给擦除掉
扩展(Extension)
- 一般用扩展来做什么
- 声明私有属性
- 声明私有方法
- 声明私有成员变量
- 扩展的
特点
:- 编译时决议
- 只以声明的形式存在,多数情况下寄生于宿主类的.m中。
- 不能为系统类添加扩展
代理
- 什么是代理:
- 含义:准确的说是一种软件设计模式
- iOS当中以@protocol形式提现
- 传递方式是一对一
- 代理的工作流程是怎样的
- 涉及的概念:委托方、协议(方法和属性)、代理方
- 一般声明为weak以规避循环引用。
通知(NSNotification)
- 什么是通知:
- 含义:是使用
观察者模式
来实现的用于跨层传递消息的机制 - 传递方式为一对多
- 含义:是使用
- 如何实现通知机制?
- 在通知中心会维护一个Map表;
KVO
- 什么事KVO技术:
- 概念:KVO是key-value observing的缩写。
- KVO是OC对
观察者模式
的一种实现 - Apple使用了isa混写(isa-swizzling)来实现KVO
- 重写的setter中添加的方法:
- -(void)willChangeValueForKey:(NSString *)key;
- -(void)didChangeValueForKey:(NSString *)key;
- Q:通过kvc设置value能否生效?
- 答案:可以
-
为什么能生效:涉及到KVC的实现原理
- Q:通过成员变量直接赋值value能否生效?
-
答案:不能;可以手动触发KVO实现;自行实现willChangeValueForKey和didChangeValueForKey方法。
- 结论:
- 使用setter方法改变值KVO才会生效。
- 使用setValue:forKey:改变值KVO才会生效。
- 成员变量直接修改需
手动添加
KVO才会生效。
KVC
- KVC的概念:KVC是key-value coding的缩写;是苹果为我们提供的一种编码技术
- 主要有两个方法:
- -(id)valueForKey:(NSString *)key; 通过key获取值
- -(void)setValue:forKey:(NSString *)key; 通过key去设置值
- 使用KVC编码技术,是否会破坏面向对象的编程思想?
- 若已知类的私有变量的名称,在外界就可通过key为实例设置或者获取值。
- 从这一点来说,是会破坏面向对象的编程思想。
- valueForKey的实现流程:
- Accessor Method 存在的判断规则:只要实现其中一种即可:
-
- Instance var 的说明:同名、相似同名变量;以下都可以获取到变量值
- _key
- _isKey
- key
- isKey
- setValue:forKey: 的实现流程:
- 判断setter方法是否存在
- 判断实例变量是否存在
- 抛出未定义key的异常
属性关键字
- 属性关键字可以分为哪几类:
- 1.读写权限 readonly、readwrite(默认)
- 2.原子性 atomic、nonatomic
- atomic:赋值和获取保证安全;但是对属性对象进行添加和移除对象是无法保证线程安全的
- 3.引用计数
- retain/strong
- unsafe_unretained/assign
- weak
- copy
- 场景:assign和weak的区别
- assign的特点:
- 1.修饰基本数据类型,如int,BOOL等
- 2.修饰对象类型时,不改变其引用计数
- 3.会产生垂直指针(野指针);(对象释放后,assign指针仍执行原对象的内存地址,这时候如果通过assign指针继续访问原对象,可能会存在内存泄露导致崩溃)
- weak的特点
- 1.不改变被修饰对象的引用计数(多数用于避免循环引用)
- 2.所指对象被释放之后会自动置为nil
- copy
- 深浅拷贝
- 浅拷贝:
- 1.会增加被拷贝对象的引用计数;
- 2.就是对
内存地址
的赋值,让目标对象指针和源对象指向同一片内存空间
- 深拷贝:
- 1.不会增加被拷贝对象的引用计数;
- 2.让目标对象指针和源对象指向
两片
内容相同
的内存空间
- 区分:
- 1.是否开辟了新的内存空间
- 2.是否影响了被拷贝对象引用计数
- copy 关键字
- @property (copy) NSMutableArray *array; 存在哪些问题?
- 如果赋值过来的是NSMutableArray,copy之后是NSArray,不可变
- 如果赋值过来的是NSArray,copy之后也是NSArray,且是浅拷贝
总结:
-
请简述分类的实现原理(运行时+函数调用顺序+同名方法生效)
-
KVO的实现原理是怎样的(观察者模式+isa混写技术)
-
能否为分类添加成员变量(关联对象技术)
-
代理和通知的区别(实现模式和传递方式)
-
分类和扩展的区别(运行、编译决议+声明方法的实现+系统类)
-
assign和weak的区别(修饰对象类型+引用计数+特点)
-
深浅拷贝的区别(新的内存空间+被拷贝对象引用计数)
最后
如果对大家有帮助,请github上follow和star,本文发布在戴超的技术博客,转载请注明出处