小編給大家分享一下Objective-C中類的數(shù)據(jù)結(jié)構(gòu)是怎么樣的,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
創(chuàng)新互聯(lián)是一家朝氣蓬勃的網(wǎng)站建設(shè)公司。公司專注于為企業(yè)提供信息化建設(shè)解決方案。從事網(wǎng)站開(kāi)發(fā),網(wǎng)站制作,網(wǎng)站設(shè)計(jì),網(wǎng)站模板,微信公眾號(hào)開(kāi)發(fā),軟件開(kāi)發(fā),成都小程序開(kāi)發(fā),10余年建站對(duì)橡塑保溫等多個(gè)行業(yè),擁有多年的網(wǎng)站推廣經(jīng)驗(yàn)。一、類的結(jié)構(gòu)
OC 中的代碼在底層實(shí)現(xiàn),使用的是 C、C++,所以要研究 OC 中的類結(jié)構(gòu),可以將 OC 的代碼轉(zhuǎn)成 C++的代碼即可。首先看一下 NSObject 的結(jié)構(gòu)是什么樣子的,創(chuàng)建一個(gè)文件并簡(jiǎn)單的編寫(xiě)如下代碼:
// CustomFile.m #importvoid test() { [NSObject alloc]; }
進(jìn)入終端,輸入指令:
clang -rewrite-objc CustomFile.m
默認(rèn)生成一個(gè) CustomFile.cpp 文件。這個(gè)指令生成的代碼會(huì)很多,也可以使用 xcrun 指令來(lái)指定一個(gè)特定的架構(gòu),這樣的:
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc CustomFile.m -o CustomFile_arm64.cpp
這樣在 CustomFile_arm64.cpp 文件中會(huì)生成一個(gè) 真機(jī)下的運(yùn)行代碼。相比之下 CustomFile_arm64.cpp 文件會(huì)比 CustomFile.cpp 小了很多,但是對(duì)于查看 NSObject 的實(shí)際結(jié)構(gòu)都是可以的。
打開(kāi)任意一個(gè) .cpp 文件,都可以找到這樣的定義:
struct NSObject_IMPL { Class isa; };
其中 Class 的定義如下:
typedef struct objc_class *Class;
再來(lái)看一下在實(shí)際中的 NSObject 類的聲明是什么樣的:
@interface NSObject{ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wobjc-interface-ivars" Class isa OBJC_ISA_AVAILABILITY; #pragma clang diagnostic pop }
簡(jiǎn)化后是這樣的:
@interface NSObject { Class isa; }
總之Class 是一個(gè)指針,NSObject_IMPL是一個(gè)結(jié)構(gòu)體,與 NSObject 在結(jié)構(gòu)上極為相似。
二、類繼承后的結(jié)構(gòu)
創(chuàng)建一個(gè) Person.m 文件,弄一個(gè)繼承于 NSObject 的 Person 類。代碼編寫(xiě)如下:
// Person.m #import// 類的申明 @interface Person : NSObject @end // 類的實(shí)現(xiàn) @implementation Person @end // 類的申明 @interface Student : Person @end // 類的實(shí)現(xiàn) @implementation Student @end
其中 Person 繼承于 NSObject,Student 繼承于 Person 于是在 .cpp 文件中找到這樣的定義:
struct Person_IMPL { struct NSObject_IMPL NSObject_IVARS; }; struct Student_IMPL { struct Person_IMPL Person_IVARS; };
NSObject_IVARS 看著這個(gè)命名就可以猜到是將父類的所有 ivar 都繼承過(guò)來(lái)了。
似乎明白了一個(gè)套路
在 NSObject 中只有一個(gè) Class 類型的成員變量 isa,在沒(méi)有自定義任何的成員屬性的情況下,繼承的子類中的 ivar 都來(lái)自于父類。
如果說(shuō)給 Person 與 Student 都定義一個(gè)成員變量,是這樣的:
struct Person_IMPL { struct NSObject_IMPL NSObject_IVARS; int _no; }; struct Student_IMPL { struct Person_IMPL Person_IVARS; int _age; };
終于對(duì) Class 的一些套路有進(jìn)一步的理解了。
三、添加方法后的結(jié)構(gòu)
創(chuàng)建一個(gè) FunClass.m 文件,編寫(xiě)代碼如下:
// FunClass.m #import// 類的申明 @interface FunClass : NSObject - (void)testInstance; + (void)testClass; @end // 類的實(shí)現(xiàn) @implementation FunClass - (void)testInstance { } + (void)testClass { } @end
最后發(fā)現(xiàn)在 .cpp 中類的結(jié)構(gòu)沒(méi)有任何的改變,是這樣的:
struct FunClass_IMPL { struct NSObject_IMPL NSObject_IVARS; };
但是我們會(huì)發(fā)現(xiàn)另外一個(gè)問(wèn)題,在 OC 中的方法變成這樣的了:
// 實(shí)例方法 _OBJC_$_INSTANCE_METHODS_FunClass __attribute__ ((used, section ("__DATA,__objc_const"))) = { sizeof(_objc_method), 1, {{(struct objc_selector *)"testInstance", "v16@0:8", (void *)_I_FunClass_testInstance}} static void _I_FunClass_testInstance(FunClass * self, SEL _cmd) { } // 類方法 _OBJC_$_CLASS_METHODS_FunClass __attribute__ ((used, section ("__DATA,__objc_const"))) = { sizeof(_objc_method), 1, {{(struct objc_selector *)"testClass", "v16@0:8", (void *)_C_FunClass_testClass}} static void _C_FunClass_testClass(Class self, SEL _cmd) { }
發(fā)現(xiàn)這幾個(gè)特點(diǎn):
1、實(shí)例方法有這個(gè):_INSTANCE_METHODS_FunClass,類方法的是這個(gè):_CLASS_METHODS_FunClass
2、兩個(gè)方法都是 static 方法
3、方法都多了兩個(gè)參數(shù):self 與_cmd,這也回答了為什么 self 與 _cmd 只能在方法中有的根本原因。
關(guān)于 方法 的這部分先介紹到這里,后期會(huì)有專門的專題。
四、自定義一個(gè) Class 與對(duì)應(yīng)的結(jié)構(gòu)體
上面啰嗦了這么多,到底是對(duì)不對(duì)呢?!那就來(lái)親自試一下吧。
這里的自定義是指不再繼承于 NSObject 了,自己搞一個(gè)結(jié)構(gòu)體。為了證明其正確性,分別定義一個(gè) HGNObject 類 與 HGNObject_IMPL 結(jié)構(gòu)體。編寫(xiě)的代碼如下:
// ==== 類的定義部分 ==== // 類的申明 @interface HGNObject : NSObject { @public int _no; int _age; } @end // 類的實(shí)現(xiàn) @implementation HGNObject @end // ==== 結(jié)構(gòu)體 ==== struct HGNObject_IMPL { Class isa_hg; int _no_hg; int _age_hg; };
做兩個(gè)試驗(yàn):
1、類轉(zhuǎn)結(jié)構(gòu)體
2、結(jié)構(gòu)體轉(zhuǎn)類
1、類轉(zhuǎn)結(jié)構(gòu)體
示例代碼如下:
// 類轉(zhuǎn)結(jié)構(gòu)體 - (void)class2Struct { // 創(chuàng)建一個(gè)對(duì)象 HGNObject* nObj = [[HGNObject alloc] init]; // 成員變量賦值 nObj->_no = 771722918; nObj->_age = 18; { // 類對(duì)象直接轉(zhuǎn)成一個(gè)結(jié)構(gòu)體 struct HGNObject_IMPL* nObj_s = (__bridge struct HGNObject_IMPL*)nObj; // 打印結(jié)構(gòu)體中的值 NSLog(@"%zd, %zd", nObj_s->_no_hg, nObj_s->_age_hg); // 打印結(jié)果: 771722918, 18 } }
通過(guò)結(jié)構(gòu)體指針能打印出在類對(duì)象中設(shè)置的值,說(shuō)明在 類轉(zhuǎn)結(jié)構(gòu)體的過(guò)程是有效的。
2、結(jié)構(gòu)體轉(zhuǎn)類
示例代碼如下:
// 結(jié)構(gòu)體轉(zhuǎn)類 - (void)struct2Class { NSLog(@"結(jié)構(gòu)體轉(zhuǎn)類"); // 生成一個(gè)結(jié)構(gòu)體 struct HGNObject_IMPL nObj_s = {0, 771722918, 20}; // 結(jié)構(gòu)體中的值打印 NSLog(@"isa_hg = %zd, _no_hg = %zd, _age_hg = %zd", nObj_s.isa_hg, nObj_s._no_hg, nObj_s._age_hg); struct HGNObject_IMPL* nObj_sPointer = &nObj_s; // 結(jié)構(gòu)體轉(zhuǎn)成對(duì)象 HGNObject* nObj = (__bridge HGNObject *)(nObj_sPointer); NSLog(@"_no_hg = %zd, _age_hg = %zd", nObj->_no, nObj->_age); }
運(yùn)行代碼,直接 crash 了:
由于 Block 解開(kāi)多年來(lái)的誤解 的慘痛教訓(xùn),所以對(duì)遇到的 crash 就會(huì)很敏感??匆幌律厦娴倪@張圖,有一個(gè)關(guān)鍵的點(diǎn)是不可以忽視的,就是這里的值:
以上是“Objective-C中類的數(shù)據(jù)結(jié)構(gòu)是怎么樣的”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)網(wǎng)站建設(shè)公司行業(yè)資訊頻道!
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)建站www.cdcxhl.com,海內(nèi)外云服務(wù)器15元起步,三天無(wú)理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場(chǎng)景需求。