一:OC对象,类及元类的理解:
1):OC对象分析
struct objc_class {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class _Nullable super_class OBJC2_UNAVAILABLE;
const char * _Nonnull name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
struct objc_ivar_list * _Nullable ivars OBJC2_UNAVAILABLE;
struct objc_method_list * _Nullable * _Nullable methodLists OBJC2_UNAVAILABLE;
struct objc_cache * _Nonnull cache OBJC2_UNAVAILABLE;
struct objc_protocol_list * _Nullable protocols OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;
每一个OC对象均包含以下信息:
isa:指向元类的objc_class的结构体指针,元类中保存有类对象的类方法;
super_class:指向父类的objc_class的结构体指针,可以通过父类找到变量与方法;
name:类名
version:类的版本信息
info:类信息,供运行期使用的标识
instance_size:类的实例变量的大小
objc_ivar_list:成员变量的链表(objc_ivar:类的成员变量(名称,类型,偏移字节,占用空间))
objc_method_list:方法链表(objc_method:SEL方法选择器,HASH后的值,IMP则是指向实现函数的指针)
objc_cache:对象使用过(缓存)的方法链表
objc_protocol_list:协议链表
2):元类分析:
a):元类定义:元类就是类对象的类,每一个类对象均有一个元类。
b):元类用途:
当调用实例方法,也就是给对象发送消息时,实际上是在对象所属类的方法链表中查找;
当调用类方法,也就是给类发送消息时,实际上是在类所属元类的方法链表中查找;
c):元类的理解:
实例对象的isa指向该实例对象的类,类对象的isa指向该类对象的元类,元类对象的isa指向根元类,根元类的isa指针指向自身。
二:OC中消息派发分析:
1):方法调用包含三要素:执行方法的对象,调用的方法以及方法所需的参数
2):方法的执行包含编译与运行两部分,因为OC是动态语言,所以OC在编译时,并不决定方法调用的三要素;而是在运行时,才决定方法执行的三要素。(静态语言,则是在编译期间就决定方法执行的三要素,且不能更改)
3):OC方法调用的实质是消息派发
以[person work]为例,本质上是执行objc_msgSend(id _Nullable self, SEL _Nonnull op, ...),其中self是执行方法的对象,SEL则是要执行的方法,...则是方法所需的参数。
调用实例方法:(以[person work]为例)
1:通过person对象的isa指针找到Person类
2:在Person类的缓存方法链表objc_cache中查找work方法(这时的work方法为实例方法)
3:若没有找到,则在Person类的方法链表objc_method_list中找到需要执行的work方法
4:若没有找到,则通过Person类的super_class指针查找Person类的父类,重复执行步骤2,3
5:若最终找到work方法,则通过IMP指针找到实现函数执行;若最终没有找到work方法,则进入OC的消息转发机制。
调用类方法:以[Person growUp]为例)
1:通过Person类的isa指针找到Person的元类
2:在元类的缓存方法链表objc_cache中查找work方法(这时的work方法为类方法)
3:若没有找到,则在元类的方法链表objc_method_list中查找work方法
4:若没有找到,则通过元类的isa指针找到根元类,重复执行步骤2,3
5:若最终没有找到work方法,则进入OC的消息转发机制
三:OC中的消息转发分析:(所有进入消息转发机制中的消息,均为未知消息)
当在消息派发机制中,没有找到要执行的方法,则会进入OC中的消息转发机制。
OC中的消息转发机制分为三步:动态方法绑定,备用接收者以及完整消息转发。
1):动态方法解析:
(当要执行的方法未实现时,可以通过动态方法解析,来动态的添加该方法及其实现)
接收者需要重写NSObject的resolveInstanceMethod:方法:
+ (BOOL)resolveInstanceMethod:(SEL)sel {
//系统注册该方法
SEL systemSel = sel_registerName(sel_getName(sel));
//接收者添加该方法,及其实现
class_addMethod(self, systemSel, (IMP)dynamicMethodIMP, "v@:");
return [super resolveInstanceMethod:systemSel];
}
首先,需向系统注册要实现的方法,然后,接收者需要添加方法实现,最后,实现动态方法解析;
2):备用接收者:
(当执行未知消息的接收者,查找不到要执行的方法,可以替换执行过未知消息的接收者作为备用接收者)
接收者需要重写forwardingTargetForSelector:方法:
- (id)forwardingTargetForSelector:(SEL)aSelector {
return [[Person alloc] init];//Person:实现aSelector方法的类
}
备用接收者不能为self,否则会出现死循环;也不能为nil,否则会进入消息转发第三步;
3):完整消息转发(NSInvocation)
(NSInvocation:完整消息的载体,记录一个消息的接收者,方法名,参数类型,参数等等,类似Method的结构体;
NSMethodSignature:方法签名,记录一个方法参数及返回值的类型(用于初始化NSInvocation类);
当动态添加方法及实现,替换备用接收者都不能处理未知消息时,只能进行完整消息的转发(forwardInvocation)。
)
接收者需要重写methodSignatureForSelector:及forwardInvocation:方法
//生成NSMethodSignature,进而用于初始化NSInvocation
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
NSMethodSignature *methodSignature = [super methodSignatureForSelector:aSelector];//获取aSelector的方法签名
if (!methodSignature) {//若存在,直接返回;若不存在,则instanceMethodSignatureForSelector:获取
if ([Person instancesRespondToSelector:aSelector]) {
methodSignature = [Person instanceMethodSignatureForSelector:aSelector];
}
}
return methodSignature;
}
//转发未知消息
- (void)forwardInvocation:(NSInvocation *)anInvocation {
if ([Person instancesRespondToSelector:anInvocation.selector]) {
[anInvocation invokeWithTarget:[[Person alloc] init]];//替换接收者,调用未知信息
}
}
四:OC消息派发,消息转发理解
1):在消息转发的步骤2,3中,均是替换未知消息的接收者,达到备用接收者响应未知消息的目的。
因此,我们可以将一些未知消息的处理放在某一个类中,当其他类需要响应这些未知消息时,可以替换备用接收者,响应这些未知消息,从而达到一个OC对象,继承不同类的方法。(OC的“多重继承”)