類方法、成員變量屬性探索

屬性、成員變量/實例變量簡介

來看下代碼實例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與SEL的關係

  • 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();
    }
複製代碼

isKindOfClass與isMemberOfClass源碼分析

代碼舉例:

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方法底層代碼結構:

    • (BOOL)isKindOfClass:(Class)cls { // 類 vs 元類 // 根元類 vs NSObject // NSObject vs NSObject // CFPerson vs 元類 (根元類) (NSObject) for (Class tcls = self->ISA(); tcls; tcls = tcls->superclass) { if (tcls == cls) return YES; } return NO;

    }

    • (BOOL)isMemberOfClass:(Class)cls { return self->ISA() == cls;

    }

    • (BOOL)isMemberOfClass:(Class)cls { return [self class] == cls;

    }

isKindOfClass方法內部先得到objc——getClass的類,而object_getClass的源碼實現是去調用當前類的objc—>getIsa(),ISA()方法中得到元類meta class的指針,

接下來還有一個循環,先判斷class是否等於meta class,不等則繼續循環是否等於super class,不等再繼續取super class,如此循環下去。

isMemberOfClass的源碼實現是拿到本身的isa指針與本身取比較是否相等。

相關文章
相關標籤/搜索