經過上一章節的學習,咱們已經瞭解了對象的底層實現,那麼類,NSObject在底層是以什麼方式存在的呢,屬性,方法,協議,都是怎麼存在於類裏面的,這一章節就來深刻了解一下數組
傳送門☞iOS底層探索-準備工做bash
傳送門☞iOS底層學習-OC對象前世此生app
建立以下類post
@interface LGPerson : NSObject{
NSString *hobby;
}
@property (nonatomic, copy) NSString *nickName;
- (void)sayHello;
+ (void)sayHappy;
@end
複製代碼
@implementation LGPerson
- (void)sayHello{
NSLog(@"LGPerson say : Hello!!!");
}
+ (void)sayHappy{
NSLog(@"LGPerson say : Happy!!!");
}
@end
複製代碼
int a = 10;
int b = 10;
LGNSLog(@"%d -- %p",a,&a);
LGNSLog(@"%d -- %p",b,&b);
輸出:
KC打印: 10 -- 0x7ffeefbff4fc
KC打印: 10 -- 0x7ffeefbff4f8
複製代碼
LGPerson *p1 = [LGPerson alloc];
LGPerson *p2 = [LGPerson alloc];
LGNSLog(@"%@ -- %p",p1,&p1);
LGNSLog(@"%@ -- %p",p2,&p2);
輸出:
KC打印: <LGPerson: 0x100544c30> -- 0x7ffeefbff4f8
KC打印: <LGPerson: 0x100545a20> -- 0x7ffeefbff4f0
複製代碼
經過以上兩個例子,能夠得出學習
// 數組指針
int c[4] = {1,2,3,4};
int *d = c;
NSLog(@"%p - %p - %p",&c,&c[0],&c[1]);
NSLog(@"%p - %p - %p",d,d+1,d+2);
for (int i = 0; i<4; i++) {
// int value = c[i];
int value = *(d+i);
LGNSLog(@"%d",value);
}
NSLog(@"指針 - 內存偏移");
複製代碼
類的實現實在編譯期就申請好內存了,因此咱們須要能夠在編譯期查看類的底層實現 編譯後經過MackOView能夠看到,LGPerson類已經生成ui
LGPerson *person = [LGPerson alloc];
Class pClass = object_getClass(person);
複製代碼
經過clang命令編譯main文件後獲得cpp文件,能夠發現,Class的底層結構是objc_class
,裏面有一個廢棄的isa指針,因此不作研究.atom
objc_class
結構以下,是繼承自
objc_object
,因此其實類也是一種對象,所謂
萬物皆對象
objc_object
定義中,NSObject是OC對objc_object的仿寫,結構是同樣的
咱們能夠看到objc_class
成員變量主要有一下四個spa
Class ISA
:主要關聯類Class superclass
:父類cache_t cache
class_data_bits_t bits
cache_t cache
爲一個結構體,所佔字節數也如圖所示,共16字節,不足以存放類中的屬性和方法,因此,屬性方法等數據,必定存儲在
class_data_bits_t bits
結構中
屬性方法等數據是存儲在class_data_bits_t bits
中,而且能夠看到class_rw_t
中的數據都是來自於此。且結構中存在屬性,方法,協議列表等,所以遇到跟蹤class_data_bits_t bits
,能夠經過指針偏移來獲取到class_data_bits_t bits
中的數據,經過結構可知,在首地址偏移32字節便可獲得3d
咱們能夠經過LLDB命令和指針偏移,一步步來探索指針
首先打印出類的16進制存儲
0x1000023b0
偏移32字節,在16進制下也就是
0x20
,獲得
0x00000001000023d0
,因爲
class_data_bits_t bits
不是對象類型,因此須要強轉一下,獲得以下地址
class_rw_t
結構的data,那麼調用方法可獲得
class_rw_t
中的內容以下
經過上面打印出的class_rw_t
中,咱們能夠看到,根據名稱,屬性應該是存儲在properties
中,經過命令打印可得下圖
list_array_tt
結構可得此爲二維數組,且根據結構可得數據應該存儲在
list
結構中
property_list_t
,可得其繼承自
entsize_list_tt
,打印其中的元素
Element first;
能夠獲得保存的類中保存的屬性
在上述探尋屬性的過程當中,咱們並無看到成員變量的保存,因此,成員變量不是保存在properties
中,應該是存在其餘的結構中,根據class_rw_t
結構思考可得,ro
中存儲成員變量的可能性較大,因此按照上述流程探尋ro
const class_ro_t
中存在一個
ivars
,成員變量應該在此
ivars
,發現其中first中已經有了咱們的屬性hobby,驗證成功
count
咱們發現爲2,因此應該還有一個成員變量,咱們能夠打印發現是
_nickName
,因此說明
屬性會自動生成對應的下劃線成員變量
經過對class_rw_t
研究,咱們發現有一個methods
元素,那麼這個頗有可能就是存放方法的列表,經過打印咱們可得
list
,能夠發現咱們的實例方法
sayHello
,此時已經驗證了方法的存儲
count
爲4,咱們看一下剩下的是什麼方法。咱們發現是屬性的get和set方法已經默認的析構方法,驗證了
屬性會自動建立get和set
經過上面的存儲探究,咱們發現並無類對象中並無類方法的存儲,且類繼承子NSObject
,且NSObject
中並無對應的類方法,因此,咱們能夠猜想,類方法是存在於元類之中的,經過類對象的isa能夠找到元類
經過上面的一系列探索,咱們可得以下結論
objc_object
class_rw_t
結構體中