來看下代碼實例html
@interface CFPerson : NSObject
{
NSString *body;
NSString *blood;
}
@property (nonatomic,copy) NSString *name;
@property (nonatomic,copy) NSString *nickName;
複製代碼
編譯後底層代碼結構markdown
extern "C" unsigned long OBJC_IVAR_$_CFPerson$_nickName;
extern "C" unsigned long OBJC_IVAR_$_CFPerson$_name;
struct CFPerson_IMPL {
struct NSObject_IMPL NSObject_IVARS;
NSString *__strong body; NSObject *__strong blood;
NSString *__strong _nickName;
NSString *__strong _name;
};
複製代碼
同時,屬性編譯會生成相應的objc_setProperty方法和當前的get方法app
static NSString * _I_CFPerson_nickName(CFPerson * self, SEL _cmd) { return (*(NSString *__strong *)((char *)self + OBJC_IVAR_$_CFPerson$_nickName)); }
extern "C" __declspec(dllimport) void objc_setProperty (id, SEL, long, id, bool, bool);
static void _I_CFPerson_setNickName_(CFPerson * self, SEL _cmd, NSString *nickName) { objc_setProperty (self, _cmd, __OFFSETOFIVAR__(struct CFPerson, _nickName), (id)nickName, 0, 1); }
static NSString * _I_CFPerson_name(CFPerson * self, SEL _cmd) { return (*(NSString *__strong *)((char *)self + OBJC_IVAR_$_CFPerson$_name)); }
// 賦值
static void _I_CFPerson_setName_(CFPerson * self, SEL _cmd, NSString *name) { (*(NSString *__strong *)((char *)self + OBJC_IVAR_$_CFPerson$_name)) = name; }
// @end
複製代碼
總結:{}裏面的內容稱爲實例變量,實例變量便是特殊的成員變量【類的實例化】ide
屬性便是帶有下劃線的成員變量+setter+getter方法函數
IMP:函數指針地址。好比一本書目錄的頁碼oop
SEL: 方法編號。如一本書的目錄名稱源碼分析
static struct /_method_list_t/ { unsigned int entsize; // sizeof(struct _objc_method) unsigned int method_count; struct _objc_method method_list[8]; } OBJC$_INSTANCE_METHODS_CFPerson attribute ((used, section ("__DATA,__objc_const"))) = { sizeof(_objc_method), 8, {{(struct objc_selector *)"nickName", "@16@0:8", (void *)_I_CFPerson_nickName}, {(struct objc_selector *)"setNickName:", "v24@0:8@16", (void *)I_CFPerson_setNickName}, {(struct objc_selector *)"name", "@16@0:8", (void *)_I_CFPerson_name}, {(struct objc_selector *)"setName:", "v24@0:8@16", (void *)I_CFPerson_setName}, {(struct objc_selector *)"nickName", "@16@0:8", (void *)_I_CFPerson_nickName}, {(struct objc_selector *)"setNickName:", "v24@0:8@16", (void *)I_CFPerson_setNickName}, {(struct objc_selector *)"name", "@16@0:8", (void *)_I_CFPerson_name}, {(struct objc_selector *)"setName:", "v24@0:8@16", (void *)I_CFPerson_setName}} };ui
static struct /_prop_list_t/ { unsigned int entsize; // sizeof(struct _prop_t) unsigned int count_of_properties; struct _prop_t prop_list[2]; } OBJC$_PROP_LIST_CFPerson attribute ((used, section ("__DATA,__objc_const"))) = { sizeof(_prop_t), 2, {{"nickName","T@"NSString",C,N,V_nickName"}, {"name","T@"NSString",&,N,V_name"}} };this
經過蘋果官方各編碼類型所指能夠知道編碼
/*
@16@0:8
@: 返回值
16 參數共用字節 16
第二個 @ :第一個參數 8
0 : 從0 開始
: : sel 8
*/
複製代碼
咱們知道,在OC裏面所謂的對象方法、實例方法,但在C/C++裏卻沒有這一說。又OC在編譯時底層必將趨於C/C++層,這個時候對象方法、實例方法就統稱爲方法。
代碼舉例
void cfObjc_copyMethodList(Class pClass){
unsigned int count = 0;
Method *methods = class_copyMethodList(pClass, &count);
for (unsigned int i=0; i < count; i++) {
Method const method = methods[i];
//獲取方法名
NSString *key = NSStringFromSelector(method_getName(method));
LGLog(@"Method, name: %@", key);
}
free(methods);
}
void cfInstanceMethod_classToMetaclass(Class pClass){
const char *className = class_getName(pClass);
Class metaClass = objc_getMetaClass(className);
Method method1 = class_getInstanceMethod(pClass, @selector(sayHello));
Method method2 = class_getInstanceMethod(metaClass, @selector(sayHello));
Method method3 = class_getInstanceMethod(pClass, @selector(sayHappy));
Method method4 = class_getInstanceMethod(metaClass, @selector(sayHappy));
LGLog(@"%s - %p-%p-%p-%p",__func__,method1,method2,method3,method4);
}
void cfClassMethod_classToMetaclass(Class pClass){
const char *className = class_getName(pClass);
Class metaClass = objc_getMetaClass(className);
Method method1 = class_getClassMethod(pClass, @selector(sayHello));//判斷pClass方法裏面是否有sayHello方法
Method method2 = class_getClassMethod(metaClass, @selector(sayHello));//判斷元類metaClass方法裏面是否有sayHello方法
Method method3 = class_getClassMethod(pClass, @selector(sayHappy));
Method method4 = class_getClassMethod(metaClass, @selector(sayHappy));
LGLog(@"%s-%p-%p-%p-%p",__func__,method1,method2,method3,method4);
}
void lgIMP_classToMetaclass(Class pClass){
const char *className = class_getName(pClass);
Class metaClass = objc_getMetaClass(className);
// - (void)sayHello;
// + (void)sayHappy;
IMP imp1 = class_getMethodImplementation(pClass, @selector(sayHello));
IMP imp2 = class_getMethodImplementation(metaClass, @selector(sayHello));
IMP imp3 = class_getMethodImplementation(pClass, @selector(sayHappy));
IMP imp4 = class_getMethodImplementation(metaClass, @selector(sayHappy));
NSLog(@"%p-%p-%p-%p",imp1,imp2,imp3,imp4);
NSLog(@"%s",__func__);
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
// 0x0000000100000000
// LGTeacher *teacher = [LGTeacher alloc];
CFPerson *person = [CFPerson alloc];
Class pClass = object_getClass(person);
lgObjc_copyMethodList(pClass);
cfInstanceMethod_classToMetaclass(pClass);
cfClassMethod_classToMetaclass(pClass);
NSLog(@"Hello, World!");
}
return 0;
}
複製代碼
打印日誌
打印結果能夠看到
這兩個方法並未查找到
Method method1 = class_getClassMethod(pClass, @selector(sayHello));
Method method2 = class_getClassMethod(metaClass, @selector(sayHello));
這兩個方法能夠查找到
Method method3 = class_getClassMethod(pClass, @selector(sayHappy));
Method method4 = class_getClassMethod(metaClass, @selector(sayHappy));
在看下class_getClassMethod方法底層實現
Method class_getClassMethod(Class cls, SEL sel)
{
if (!cls || !sel) return nil;
return class_getInstanceMethod(cls->getMeta(), sel);
}
獲得一個類的類方法就至關於獲得一個元類的實例方法
複製代碼
再往下走
static method_t *getMethod_nolock(Class cls, SEL sel)
{
method_t *m = nil;
runtimeLock.assertLocked();
// fixme nil cls?
// fixme nil sel?
ASSERT(cls->isRealized());
while (cls && ((m = getMethodNoSuper_nolock(cls, sel))) == nil) {
cls = cls->superclass;
}
return m;
}
若是是元類,則不會再遞歸下去,不然會一直循環
// NOT identical to this->ISA when this is a metaclass
Class getMeta() {
if (isMetaClass()) return (Class)this;
else return this->ISA();
}
複製代碼
代碼舉例:
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
BOOL re1 = [(id)[NSObject class] isKindOfClass:[NSObject class]]; //
BOOL re2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]]; //
BOOL re3 = [(id)[CFPerson class] isKindOfClass:[CFPerson class]]; //
BOOL re4 = [(id)[CFPerson class] isMemberOfClass:[CFPerson class]]; //
NSLog(@" re1 :%hhd\n re2 :%hhd\n re3 :%hhd\n re4 :%hhd\n",re1,re2,re3,re4);
BOOL re5 = [(id)[NSObject alloc] isKindOfClass:[NSObject class]]; //
BOOL re6 = [(id)[NSObject alloc] isMemberOfClass:[NSObject class]]; //
BOOL re7 = [(id)[CFPerson alloc] isKindOfClass:[CFPerson class]]; //
BOOL re8 = [(id)[CFPerson alloc] isMemberOfClass:[CFPerson class]]; //
NSLog(@" re5 :%hhd\n re6 :%hhd\n re7 :%hhd\n re8 :%hhd\n",re5,re6,re7,re8);
}
return 0;
}
複製代碼
打印結果:
isKindOfClass和isMemberOfClass方法底層代碼結構:
}
}
}
isKindOfClass方法內部先得到objc——getClass的類,而object_getClass的源碼實現是去調用當前類的objc—>getIsa(),ISA()方法中得到元類meta class的指針,
接下來還有一個循環,先判斷class是否等於meta class,不等則繼續循環是否等於super class,不等再繼續取super class,如此循環下去。
isMemberOfClass的源碼實現是拿到本身的isa指針與本身取比較是否相等。