005:类原理分析下
问题
目录
1:class_ro_t-->>class_rw_t-->>class_rw_ext_t
2:iskindOfClass & isMemberOfClass 的理解
3:class_getClassMethod源码
预备
正文
1:class_ro_t-->>class_rw_t-->>class_rw_ext_t
1.1:当类第一次从磁盘加载到内存,编译的时候,为class_ro_t
1.2:第一次使用runtime的时候是class_rw_t
1.3:将需要动态更新的部分提取出来,class_rw_ext_t
2: 简单面试题
1:类存在几份?
由于类的信息
在内存
中永远只存在一份
,所以 类对象只有一份
2: objc_object 与 对象的关系
所有的对象
都是以 objc_object
为模板继承
过来的
所有的对象 是 来自 NSObject
(OC) ,但是真正到底层的 是一个objc_object(C/C++)
的结构体类型
【总结】 objc_object
与 对象
的关系
是 继承
关系
3:什么是 属性 & 成员变量 & 实例变量 ?
-
属性
(property):在OC中是通过@property开头定义
,且是带下划线成员变量
+setter
+getter
方法的变量 -
成员变量
(ivar):在OC的类中{}中定义
的,且没有下划线
的变量 -
实例变量
:通过当前对象类型,具备实例化的变量
,是一种特殊的成员变量
,例如 NSObject、UILabel、UIButton等
【附加】成员变量 和 实例变量什么区别?
-
实例变量
(即成员变量
中的对象变量
就是实例变量
):以实例对象实例化来的,是一种特殊的成员变量
-
NSString
是常量
类型, 因为不能添加属性
,如果定义在类中的{}
中,是成员变量
-
成员变量
中 除去基本数据类型、NSString
,其他都是实例变量
(即可以添加属性
的成员变量
),实例变量主要是判断是不是对象
3:class_getInstanceMethod和class_getClassMethod
class_getInstanceMethod
:获取实例方法
,如果指定的类
或其父类不包含
带有指定选择器的实例方法
,则为NULL
class_getClassMethod
:获取类方法
,如果指定的类
或其父类不包含
具有指定选择器的类方法
,则为NULL
。class_getMethodImplementation
:获取方法
的具体实现
,如果未查找到
,则进行消息转发
4:iskindOfClass & isMemberOfClass 的理解
@implementation LCPerson : NSObject BOOL re1 = [(id)[NSObject class] isKindOfClass:[NSObject class]]; // 1 BOOL re2 = [(id)[LCPerson class] isKindOfClass:[LCPerson class]]; // 0 BOOL re3 = [(id)[NSObject alloc] isKindOfClass:[NSObject class]]; // NSObject和实例的元类比较 NSObject 1 BOOL re4 = [(id)[LCPerson alloc] isKindOfClass:[LCPerson class]]; // 1 NSLog(@" re1 :%hhd\n re2 :%hhd\n re3 :%hhd\n re4 :%hhd\n",re1,re2,re3,re4); BOOL re5 = [(id)[NSObject class] isMemberOfClass:[NSObject class]]; // 0 BOOL re6 = [(id)[LCPerson class] isMemberOfClass:[LCPerson class]]; // 0 BOOL re7 = [(id)[NSObject alloc] isMemberOfClass:[NSObject class]]; // 1 BOOL re8 = [(id)[LCPerson alloc] isMemberOfClass:[LCPerson class]]; // 1 NSLog(@" re5 :%hhd\n re6 :%hhd\n re7 :%hhd\n re8 :%hhd\n",re5,re6,re7,re8);
3:源码解析
isKindOfClass 源码解析(实例方法 & 类方法)
//--isKindOfClass---类方法、对象方法 //+ isKindOfClass:第一次比较是 获取类的元类 与 传入类对比,再次之后的对比是获取上次结果的父类 与 传入 类进行对比
//判断的当前类
的元类
是否与条件类
相等,如果不相等,会走当前类的元类
的父类
继续判断是否与条件类
相等
+ (BOOL)isKindOfClass:(Class)cls { // 获取类的元类 vs 传入类 // 根元类 vs 传入类 // 根类 vs 传入类 // 举例:LGPerson vs 元类 (根元类) (NSObject) for (Class tcls = self->ISA(); tcls; tcls = tcls->superclass) { if (tcls == cls) return YES; } return NO; } //- isKindOfClass:第一次是获取对象类 与 传入类对比,如果不相等,后续对比是继续获取上次 类的父类 与传入类进行对比
//判断当前对象所属的类
是否与条件类
相等,如果不相等,会走当前对象所属的类
的父类
继续判断与条件类
是否相等,是一个实例方法
- (BOOL)isKindOfClass:(Class)cls { /* 获取对象的类 vs 传入的类 父类 vs 传入的类 根类 vs 传入的类 nil vs 传入的类 */ for (Class tcls = [self class]; tcls; tcls = tcls->superclass) { if (tcls == cls) return YES; } return NO; }
isMemberOfClass 源码解析(实例方法 & 类方法)
//-----类方法 //+ isMemberOfClass : 获取类的元类,与 传入类对比 + (BOOL)isMemberOfClass:(Class)cls { return self->ISA() == cls; } //-----实例方法 //- isMemberOfClass : 获取对象的类,与 传入类对比 - (BOOL)isMemberOfClass:(Class)cls { return [self class] == cls; }
isKindOfClass(for循环)
- 类方法:
元类(isa) --> 根元类(父类) --> 根类(父类) --> nil(父类)
与传入类
的对比【判断元类】- 实例方法:
对象的类 --> 父类 --> 根类 --> nil
与传入类
的对比【判断实例所属的类】对象所属的类和对象实例的isa指针比较、
isMemberOfClass(不循环)
- 类方法:
类的元类
与传入类
对比【判断元类】- 实例方法:
对象的父类
与传入类
对比【判断实例所属的类】
类方法:判断的是isa,元类
实例方法判断的是都是通过[self class] 和自己的类来进行对比。永远是1.
iskindofClass有继承的关系。
3: class_getClassMethod
的源码:
Method class_getClassMethod(Class cls, SEL sel) { if (!cls || !sel) return nil; return class_getInstanceMethod(cls->getMeta(), sel); } --- // NOT identical to this->ISA when this is a metaclass Class getMeta() { if (isMetaClass()) return (Class)this; else return this->ISA(); }
class_getClassMethod
的流程:
class_getClassMethod
里面调用的也是class_getInstanceMethod
;- 只不过传的类是
cls->getMeta()
这个方法返回的; getMeta
如果是元类,返回的就是自己;getMeta
如果不是元类,返回的是ISA()
;- 类的
ISA()
返回的是 该类的元类;
class_getClassMethod总结:
- 如果传的类,里面是获取的元类的
class_getInstanceMethod
方法。也既类方法是从元类里面去找的。 - 如果传的是元类,直接用元类调用
class_getInstanceMethod
方法。
注意