iOS 底層探究:屬性與成員變量

這是我參與8月更文挑戰的第6天,活動詳情查看:8月更文挑戰緩存

1.WWDC 類結構的優化

WWDC關於runtime裏面關於類的優化裏面提到了clean memorydirty memorymarkdown

1.1 Clean Memory

  • 加載後不會再改變的內存
  • class_ro_t是隻讀的,屬於Clean Memory
  • 可移除,從而節省更多內存空間。若是你有須要,系統能夠從磁盤中從新加載。

1.2 Dirty Memory

  • 進程運行時會發生變化的內存
  • 類結構體一旦被使用就是Dirty Memory,由於運行時會寫入新的數據,例如:方法緩存
  • Dirty Memory是類數據被分爲兩部分的緣由

Dirty MemoryClean Memory更昂貴,由於在進程運行的整個過程當中,都須要被保留。經過分離出那些永遠不會改變的數據,將大部分的類數據存儲爲Clean Memory。 類結構一經使用就會變成Dirty Memory,由於運行時會向他寫入新的數據,例如建立一個新的方法緩存並從類中指向它。因此class_rw_t出現了,它能夠讀寫類的繼承關係,跟蹤類的方法,屬性,協議等,單隻有大約10%的類會去修改它的方法,因此class_rw_ext_t出現了,90%內將不須要class_rw_ext_t,這能節省class_rw_t一半的空間。以下圖app

image.png

2.屬性和成員變量

在iOS5以前,定義成員變量是在大括號裏定義,同時用了@property聲明,並且還在@implementation中使用@synthesize方法。緣由是蘋果將默認編譯器從GCC轉換爲LLVM(low level virtual machine),纔再也不須要爲屬性聲明實例變量了。 在沒有更改以前,屬性的正常寫法須要成員變量+@property+@synthesize成員便利那個三個步驟。更換爲LLVM以後,編譯器在編譯過程當中發現沒有新的實例變量後,就會生成一個下劃線開頭的實例變量。所以如今部門沒必要再聲明一個實例變量。 如今@property聲明的屬性不單單給咱們生成一個_類型的成員變量,同時也會生成setter/getter方法。ide

  • 屬性=帶下劃線成員變量+setter+getter方法。
  • 實例變量:特殊的成員變量(類的實例化)。

2.1 成員變量與屬性的區別

  • 成員變量:在底層只是變量的聲明
  • 屬性:系統會自動在底層添加_屬性名變量,同時生成setter和getter方法

2.2 成員變量與實例變量的區別

  • 實例變量是一種特殊的成員變量
  • 成員變量爲基本數據類型
  • 實例變量爲對象類型,例如:NSObject類型
  • NSString爲常量類型,屬於成員變量

3.isKindOfClass

3.1方法的做用

不管調用類對象仍是實例對象的isKindOfClass方法,入口函數統一爲 objc_opt_isKindOfClass 找到objc_opt_isKindOfClass函數函數

BOOL 
objc_opt_isKindOfClass(id obj, Class otherClass) 
{ 
#if __OBJC2__ 
    if (slowpath(!obj)) return NO; 
    Class cls = obj->getIsa(); 
    if (fastpath(!cls->hasCustomCore())) { 
        for (Class tcls = cls; tcls; tcls = tcls->getSuperclass()) { 
            if (tcls == otherClass) return YES; 
         } 
         return NO; 
     } 
#endif 
    return ((BOOL(*)(id, SEL, Class))objc_msgSend)(obj, @selector(isKindOfClass:), otherClass); 
}
複製代碼
  • 獲取對象isa指向的類,和傳入的Class對比
  • 遍歷對象isa指向類的父類,和傳入的Class對比

isKindOfClass方法的做用:oop

  • 類對象
    • 元類 VS Class
    • 遍歷:類的父類 VS Class
  • 實例對象
    • 類 VS Class
    • 遍歷:類的父類 VS Class

3.2驗證類對象與實例對象

示例:封裝isKindOfClass函數post

void isKindOfClassDemo(){ 
    BOOL re1 = [(id)[NSObject class] isKindOfClass:[NSObject class]]; 
    BOOL re2 = [(id)[LGPerson class] isKindOfClass:[LGPerson class]]; 
    NSLog(@"NSObject類對象:%hhd", re1); 
    NSLog(@"LGPerson類對象:%hhd", re2); 
    BOOL re3 = [(id)[NSObject alloc] isKindOfClass:[NSObject class]]; 
    BOOL re4 = [(id)[LGPerson alloc] isKindOfClass:[LGPerson class]]; 
    NSLog(@"NSObject實例對象:%hhd", re3); 
    NSLog(@"LGPerson實例對象:%hhd", re4); }
複製代碼

調用isKindOfClassDemo函數優化

isKindOfClassDemo(); 
------------------------- 
NSObject類對象:1 
LGPerson類對象:0 
NSObject實例對象:1 
LGPerson實例對象:1
複製代碼

3.3分析

  • res1傳入的是NSObject的類,獲取元類與NSObject不等,繼續尋找獲取元類的父類爲NSObject與傳入的值相等,返回true。
    • res2傳入的是LGPerson的類,獲取元類與LGPerson不等,繼續尋找獲取元類的父類爲NSObject的元類,與傳入的值依舊不等,繼續往上NSObject元類的父類爲NSObject依舊不等,再往上就是nil,最後返回false
  • res3 傳入的是NSObject的實例,獲取對象的類,與NSObject相等,返回true
  • res4 傳入的是LGPerson的實例,獲取對象的類,與LGPerson相等,返回true

4 isMemberOfClass

4.1方法的做用

找到isMemberOfClass方法spa

+ (BOOL)isMemberOfClass:(Class)cls { 
    return self->ISA() == cls; 
} 
- (BOOL)isMemberOfClass:(Class)cls { 
    return [self class] == cls; 
}
複製代碼
  • 類方法:獲取類的元類,和傳入的cls對比
  • 實例方法:獲取對象所屬的類,和傳入的cls對比

4.2驗證類對象與實例對象

封裝isMemberOfClass方法code

void isMemberOfClassDemo(){ 
    BOOL re1 = [(id)[NSObject class] isMemberOfClass:[NSObject class]]; 
    BOOL re2 = [(id)[LGPerson class] isMemberOfClass:[LGPerson class]]; 
    NSLog(@"NSObject類對象:%hhd", re1); 
    NSLog(@"LGPerson類對象:%hhd", re2); 
    BOOL re3 = [(id)[NSObject alloc] isMemberOfClass:[NSObject class]]; 
    BOOL re4 = [(id)[LGPerson alloc] isMemberOfClass:[LGPerson class]]; 
    NSLog(@"NSObject實例對象:%hhd", re3); 
    NSLog(@"LGPerson實例對象:%hhd", re4); 
}
複製代碼

調用isMemberOfClassDemo函數

isMemberOfClassDemo(); 
------------------------- 
NSObject類對象:0 
LGPerson類對象:0 
NSObject實例對象:1 
LGPerson實例對象:1
複製代碼

4.3分析

  • res1是NSObject類調用類方法isMemberOfClassNSObject類比較,很明顯,NSObject的元類NSObject自己並不相等,因此返回false
  • res2是LGPerson類調用類方法isMemberOfClassLGPerson類比較,LGPerson的元類LGPerson自己並不相等,因此返回false
  • res3是NSObject的實例調用實例方法isMemberOfClassNSObject類比較,明顯她們是相同的,因此返回true
  • res4是LGPerson的實例調用實例方法isMemberOfClassLGPerson類比較,明顯的他們是相同的,因此返回true
相關文章
相關標籤/搜索