一钾虐、準(zhǔn)備工作
- objc4可編譯源碼,可直接跳到文章最后笋庄,下載調(diào)試好的源碼
- 在源碼中創(chuàng)建類(lèi)
GomuPerson
GomuPerson.h
@interface GomuPerson : NSObject
{
//: 成員變量
NSString *hobby;
//: 特殊的成員變量效扫,實(shí)例變量,能夠被實(shí)例的對(duì)象的成員變量叫實(shí)例變量
NSObject *obj;
}
//: 創(chuàng)建屬性
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSString *sex;
//: 創(chuàng)建實(shí)例方法直砂、類(lèi)方法
- (void)sayNO;
+ (void)sayLove;
GomuPerson.m
//: 實(shí)現(xiàn)方法
- (void)sayNO{}
+ (void)sayLove{}
@end
二菌仁、通過(guò)runtime的api拿方法、屬性静暂、成員變量
2.1 通過(guò)gomu_copyMethodList
拿GomuPerson
里面的方法
//: 打印類(lèi)中的所有方法
void gomu_copyMethodList(Class class){
unsigned int count = 0;
Method *methods = class_copyMethodList(class, &count);
for (unsigned int i = 0; i < count; i++) {
Method const method = methods[i];
//: 獲取方法名
NSString *methodName = NSStringFromSelector(method_getName(method));
GOMULog(@"Method, name: %@",methodName);
}
free(methods);
}
//: 調(diào)用方法
GomuPerson *p = [GomuPerson alloc];
//: 獲取實(shí)例方法
gomu_copyMethodList(object_getClass(p));
//: 打印
Method, name: sayNO
Method, name: sex
Method, name: setSex:
Method, name: .cxx_destruct
Method, name: name
Method, name: setName:
//: 獲取類(lèi)方法
gomu_copyMethodList(object_getClass([GomuPerson class]));
//: 打印
Method, name: sayLove
結(jié)論:
對(duì)象方法
存在類(lèi)
中- 系統(tǒng)在編譯中會(huì)自動(dòng)
生成
屬性的get
济丘、set
方法- 系統(tǒng)在編譯中也會(huì)
生成c++
的.cxx_destruct
方法類(lèi)方法
存在元類(lèi)
中
2.2 通過(guò)gomu_copyPropertyList
拿GomuPerson里面的屬性
#pragma mark -- 獲取屬性
void gomu_copyPropertyList(Class class){
unsigned int count = 0;
objc_property_t *propertys = class_copyPropertyList(class, &count);
for (unsigned int i = 0; i < count; i++) {
objc_property_t property = propertys[i];
//: 獲取屬性
const char *propertyName = property_getName(property);
GOMULog(@"Property, name: %s",propertyName);
}
free(propertys);
}
//: 調(diào)用方法
GomuPerson *p = [GomuPerson alloc];
//: 獲取屬性
gomu_copyPropertyList(object_getClass(p));
//: 打印
Property, name: name
Property, name: sex
結(jié)論:
屬性
存在PropertyList
中成員變量
不存在PropertyList
中
2.3 通過(guò)gomu_copyIvarList
拿GomuPerson里面的成員變量
#pragma mark -- 獲取成員變量
void gomu_copyIvarList(Class class){
unsigned int count = 0;
Ivar *ivars = class_copyIvarList(class, &count);
for (unsigned int i = 0; i < count; i++) {
Ivar const ivar = ivars[i];
//: 獲取成員變量
const char *ivarName = ivar_getName(ivar);
GOMULog(@"Ivar, name: %s",ivarName);
}
free(ivars);
}
//: 調(diào)用方法
GomuPerson *p = [GomuPerson alloc];
//: 獲取屬性
gomu_copyIvarList(object_getClass(p));
//: 打印
Ivar, name: hobby
Ivar, name: obj
Ivar, name: _name
Ivar, name: _sex
結(jié)論
成員變量
存在IvarList
中- 系統(tǒng)編譯中會(huì)自動(dòng)給
屬性
生成帶_
的成員變量
2.4 通過(guò)class_getInstanceMethod
判斷對(duì)象方法和類(lèi)方法的歸屬
void gomuInstanceMethod_classToMetaclass(Class pClass){
//: 獲取元類(lèi)
const char *className = class_getName(pClass);
Class metaClass = objc_getMetaClass(className);
//: 判斷類(lèi)中是否有對(duì)象方法`sayNO`:有
Method method1 = class_getInstanceMethod(pClass, @selector(sayNO));
//: 判斷元類(lèi)中是否有對(duì)象方法`sayNO`:沒(méi)有
Method method2 = class_getInstanceMethod(metaClass, @selector(sayNO));
//: 判斷類(lèi)中是否有類(lèi)方法`sayLove`的對(duì)象方法:沒(méi)有
Method method3 = class_getInstanceMethod(pClass, @selector(sayLove));
//: 判斷類(lèi)元中是否有類(lèi)方法`sayLove`的對(duì)象方法:有
Method method4 = class_getInstanceMethod(metaClass, @selector(sayLove));
GOMULog(@"%s : %p - %p - %p - %p",__func__,method1,method2,method3,method4);
GOMULog(@"%s : %p - %p - %p - %p",__func__,method1,method2,method3,method4);
//: 調(diào)用
gomuInstanceMethod_classToMetaclass(pClass);
//: 打印
gomuInstanceMethod_classToMetaclass : 0x1000031e0 - 0x0 - 0x0 - 0x100003178
}
結(jié)論:
對(duì)象方法
存在類(lèi)
中類(lèi)方法
存在元類(lèi)
,并且以對(duì)象方法
的形式存在元類(lèi)
中
2.5 通過(guò)class_getClassMethod
判斷對(duì)象方法和類(lèi)方法的歸屬
void gomuClassMethod_classToMetaclass(Class pClass){
//: 獲取元類(lèi)
const char *className = class_getName(pClass);
Class metaClass = objc_getMetaClass(className);
//: 判斷類(lèi)中是否有對(duì)象方法`sayNO`的類(lèi)方法:沒(méi)有
Method method1 = class_getClassMethod(pClass, @selector(sayNO));
//: 判斷元類(lèi)中是否有對(duì)象方法`sayNO`的類(lèi)方法:沒(méi)有
Method method2 = class_getClassMethod(metaClass, @selector(sayNO));
//: 判斷類(lèi)中是否有類(lèi)方法`sayLove`:有
Method method3 = class_getClassMethod(pClass, @selector(sayLove));
//: 判斷元類(lèi)中是否有類(lèi)方法`sayLove`:有
Method method4 = class_getClassMethod(metaClass, @selector(sayLove));
GOMULog(@"%s : %p - %p - %p - %p",__func__,method1,method2,method3,method4);
//: 調(diào)用
gomuClassMethod_classToMetaclass(pClass);
//: 打印
gomuClassMethod_classToMetaclass : 0x0 - 0x0 - 0x100003180 - 0x100003180
}
結(jié)論:
- 不管
類(lèi)
還是元類(lèi)
中,都不會(huì)有對(duì)象方法
的類(lèi)方法
類(lèi)
和元類(lèi)
中摹迷,都有類(lèi)方法
2.5.1 元類(lèi)中為什么會(huì)有類(lèi)方法疟赊,不是說(shuō)類(lèi)方法在元類(lèi)是以對(duì)象方法的形成存在的嗎,進(jìn)入class_getClassMethod
內(nèi)部查看源碼
Method class_getClassMethod(Class cls, SEL sel)
{
if (!cls || !sel) return nil;
//: 當(dāng)cls是元類(lèi)峡碉,走到這里近哟,getMeta()返回元類(lèi)
//: 所以 class_getClassMethod 傳入元類(lèi)相當(dāng)于 class_getInstanceMethod傳入元類(lèi)
return class_getInstanceMethod(cls->getMeta(), sel);
}
//: 如果是元類(lèi),則直接返回自己
Class getMeta() {
if (isMetaClass()) return (Class)this;
else return this->ISA();
}
結(jié)論:
- 當(dāng)
class_getClassMethod
的cls
傳入的是元類(lèi)异赫,則會(huì)調(diào)用class_getInstanceMethod
椅挣,執(zhí)行到cls->getMeta()
返回自己。class_getClassMethod(metaClass, @selector(sayLove))
等價(jià)于class_getInstanceMethod(metaClass, @selector(sayLove));
類(lèi)方法
在元類(lèi)
中還是以對(duì)象方法
的方法存在
2.6 查看類(lèi)方法/對(duì)象
方法在類(lèi)/元類(lèi)
中的IMP
void gomuIMP_classToMetaclass(Class pClass){
//: 獲取元類(lèi)
const char *className = class_getName(pClass);
Class metaClass = objc_getMetaClass(className);
//: 在類(lèi)中獲取對(duì)象方法`sayNO`的IMP
IMP imp1 = class_getMethodImplementation(pClass, @selector(sayNO));
//: 在元類(lèi)中獲取對(duì)象方法`sayNO`的IMP
IMP imp2 = class_getMethodImplementation(metaClass, @selector(sayNO));
//: 在類(lèi)中獲取類(lèi)方法`sayLove`的IMP
IMP imp3 = class_getMethodImplementation(pClass, @selector(sayLove));
//: 在元類(lèi)中獲取類(lèi)方法`sayLove`的IMP
IMP imp4 = class_getMethodImplementation(metaClass, @selector(sayLove));
GOMULog(@"%p - %p - %p - %p",imp1,imp2,imp3,imp4);
//: 調(diào)用
gomuIMP_classToMetaclass(pClass);
//: 打印
0x100001b90 - 0x1002c4140 - 0x1002c4140 - 0x100001b80
}
結(jié)論:
- 對(duì)象方法
sayNO
在GomuPerson
中找到了IMP
- 對(duì)象方法
sayNO
在GomuPerson
的元類(lèi)中找到了IMP
- 類(lèi)方法
sayLove
在GomuPerson
的中找到了IMP
- 類(lèi)方法
sayLove
在GomuPerson
的元類(lèi)中找到了IMP
問(wèn)題:imp1,imp4都能理解塔拳,imp2,imp3怎么也有IMP鼠证?
2.6.1 第一種方式探索:查看源碼
IMP class_getMethodImplementation(Class cls, SEL sel)
{
IMP imp;
if (!cls || !sel) return nil;
imp = lookUpImpOrNil(nil, sel, cls, LOOKUP_INITIALIZE | LOOKUP_RESOLVER);
// Translate forwarding function to C-callable external version
//: 當(dāng)沒(méi)有找到IMP,會(huì)返回一個(gè)`_objc_msgForward`
if (!imp) {
return _objc_msgForward;
}
return imp;
}
- 從源碼不難看出靠抑,IMP是肯定存在的量九,只是有可能這個(gè)IMP可能是
_objc_msgForward
類(lèi)型
2.6.2 第一種方式探索:lldb調(diào)試
//: 下斷點(diǎn),分別打印
(lldb) p/x imp1
(IMP) $0 = 0x0000000100001b90 (GomuTest`-[GomuPerson sayNO])
(lldb) p/x imp2
(IMP) $1 = 0x00000001002c4140 (libobjc.A.dylib`_objc_msgForward)
(lldb) p/x imp3
(IMP) $2 = 0x00000001002c4140 (libobjc.A.dylib`_objc_msgForward)
(lldb) p/x imp4
(IMP) $3 = 0x0000000100001b80 (GomuTest`+[GomuPerson sayLove])
結(jié)論:
對(duì)象方法的imp
在類(lèi)
中可以拿到類(lèi)方法
的imp
在元類(lèi)
中可以拿到imp
不會(huì)為空颂碧,為空會(huì)默認(rèn)_objc_msgForward
三荠列、拓展知識(shí)
- imp : 函數(shù)指針地址
- sel : 方法編號(hào)