麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 系統 > iOS > 正文

深入理解Objective-C中類的數據結構

2019-10-21 18:41:07
字體:
來源:轉載
供稿:網友

一、類的結構

OC 中的代碼在底層實現,使用的是 C、C++,所以要研究 OC 中的類結構,可以將 OC 的代碼轉成 C++的代碼即可。首先看一下 NSObject 的結構是什么樣子的,創建一個文件并簡單的編寫如下代碼:

// CustomFile.m#import <Foundation/Foundation.h>void test() { [NSObject alloc];}

進入終端,輸入指令:

clang -rewrite-objc CustomFile.m

默認生成一個 CustomFile.cpp 文件。這個指令生成的代碼會很多,也可以使用 xcrun 指令來指定一個特定的架構,這樣的:

xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc CustomFile.m -o CustomFile_arm64.cpp

這樣在 CustomFile_arm64.cpp 文件中會生成一個 真機下的運行代碼。相比之下 CustomFile_arm64.cpp 文件會比 CustomFile.cpp 小了很多,但是對于查看 NSObject 的實際結構都是可以的。

打開任意一個 .cpp 文件,都可以找到這樣的定義:

struct NSObject_IMPL { Class isa;};

其中 Class 的定義如下:

typedef struct objc_class *Class;

再來看一下在實際中的 NSObject 類的聲明是什么樣的:

@interface NSObject <NSObject> {#pragma clang diagnostic push#pragma clang diagnostic ignored "-Wobjc-interface-ivars" Class isa OBJC_ISA_AVAILABILITY;#pragma clang diagnostic pop}

簡化后是這樣的:

@interface NSObject { Class isa;}

總之Class 是一個指針,NSObject_IMPL是一個結構體,與 NSObject 在結構上極為相似。

二、類繼承后的結構

創建一個 Person.m 文件,弄一個繼承于 NSObject 的 Person 類。代碼編寫如下:

// Person.m#import <Foundation/Foundation.h>// 類的申明@interface Person : NSObject@end// 類的實現@implementation Person@end// 類的申明@interface Student : Person@end// 類的實現@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 看著這個命名就可以猜到是將父類的所有 ivar 都繼承過來了。

似乎明白了一個套路

在 NSObject 中只有一個 Class 類型的成員變量 isa,在沒有自定義任何的成員屬性的情況下,繼承的子類中的 ivar 都來自于父類。

如果說給 Person 與 Student 都定義一個成員變量,是這樣的:

struct Person_IMPL { struct NSObject_IMPL NSObject_IVARS; int _no;};struct Student_IMPL { struct Person_IMPL Person_IVARS; int _age;};

終于對 Class 的一些套路有進一步的理解了。

三、添加方法后的結構

創建一個 FunClass.m 文件,編寫代碼如下:

// FunClass.m#import <Foundation/Foundation.h>// 類的申明@interface FunClass : NSObject- (void)testInstance;+ (void)testClass;@end// 類的實現@implementation FunClass- (void)testInstance { }+ (void)testClass { }@end

最后發現在 .cpp 中類的結構沒有任何的改變,是這樣的:

struct FunClass_IMPL { struct NSObject_IMPL NSObject_IVARS;};

但是我們會發現另外一個問題,在 OC 中的方法變成這樣的了:

// 實例方法_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) {}

發現這幾個特點:

     1、實例方法有這個:_INSTANCE_METHODS_FunClass,類方法的是這個:_CLASS_METHODS_FunClass

     2、兩個方法都是 static 方法

     3、方法都多了兩個參數:self 與_cmd,這也回答了為什么 self 與 _cmd 只能在方法中有的根本原因。

關于 方法 的這部分先介紹到這里,后期會有專門的專題。

四、自定義一個 Class 與對應的結構體

上面啰嗦了這么多,到底是對不對呢?!那就來親自試一下吧。

這里的自定義是指不再繼承于 NSObject 了,自己搞一個結構體。為了證明其正確性,分別定義一個 HGNObject 類 與 HGNObject_IMPL 結構體。編寫的代碼如下:

// ==== 類的定義部分 ====// 類的申明@interface HGNObject : NSObject { @public int _no; int _age;}@end// 類的實現@implementation HGNObject@end// ==== 結構體 ====struct HGNObject_IMPL { Class isa_hg; int _no_hg; int _age_hg;};

做兩個試驗:

1、類轉結構體

2、結構體轉類

1、類轉結構體

示例代碼如下:

// 類轉結構體- (void)class2Struct { // 創建一個對象 HGNObject* nObj = [[HGNObject alloc] init]; // 成員變量賦值 nObj->_no = 771722918; nObj->_age = 18;  { // 類對象直接轉成一個結構體 struct HGNObject_IMPL* nObj_s = (__bridge struct HGNObject_IMPL*)nObj; // 打印結構體中的值 NSLog(@"%zd, %zd", nObj_s->_no_hg, nObj_s->_age_hg); // 打印結果: 771722918, 18 }}

通過結構體指針能打印出在類對象中設置的值,說明在 類轉結構體的過程是有效的。

2、結構體轉類

示例代碼如下:

// 結構體轉類- (void)struct2Class { NSLog(@"結構體轉類"); // 生成一個結構體 struct HGNObject_IMPL nObj_s = {0, 771722918, 20}; // 結構體中的值打印 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;  // 結構體轉成對象 HGNObject* nObj = (__bridge HGNObject *)(nObj_sPointer);  NSLog(@"_no_hg = %zd, _age_hg = %zd", nObj->_no, nObj->_age);}

運行代碼,直接 crash 了:

Objective-C,數據結構

由于 Block 解開多年來的誤解 的慘痛教訓,所以對遇到的 crash 就會很敏感。看一下上面的這張圖,有一個關鍵的點是不可以忽視的,就是這里的值:

Objective-C,數據結構

簡單的分析(我這里的分析都是猜的,暫時我也不知道,【抱歉抱歉抱歉】)

nObj_s 是有正確的值的,說明 nObj_sPointer 指針也是沒有問題的,但是為什么會報一個壞地址訪問錯誤呢?并且 address 的值每次都是一樣的 0x20。我猜想:在轉化的過程中不僅僅是一個簡單的賦值操作、可能還做了其他的地址訪問操作,這個操作很有可能與 +alloc 方法中操作有關,畢竟在 OC 中正常的創建一個對象必先 +alloc方法,對于 +alloc中都做了什么事,暫時我還不清楚,所以這里我是蒙的。各位大神若有新的理解,望指教!

所以在第一個實驗中的 類轉結構體 中是有效的,也許是一個偶然。畢竟我們在上面的 .cpp 文件中查看數據結構的時候也只是看了一個大概,并沒有看全部的。

OK,忘記本節(自定義一個 Class 與對應的結構體)中遇到的不愉快, 至少 類轉結構體 是有效的,也能說明一些問題。

本系列的文章,有:

1、Objective-C 中類的數據結構

2、Objective-C 中實例所占內存的大小

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對VEVB武林網的支持。


注:相關教程知識閱讀請移步到IOS開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 一级黄色免费观看 | 极品销魂一区二区三区 | 老a影视网站在线观看免费 国产精品久久久久久久久久尿 | 天天鲁在线视频免费观看 | 欧美成人精品一级 | 四虎久草 | 欧美综合在线观看 | 国产视频在线观看一区二区三区 | 免费观看三级毛片 | 黄色网战入口 | 黄污网站在线观看 | 一级黄色性感片 | 成年免费视频黄网站在线观看 | 久久久久久久久免费 | 免费看性xxx高清视频自由 | a级高清免费毛片av在线 | 久久久久亚洲国产精品 | 久草在线综合 | 欧美a黄 | 亚洲特黄a级毛片在线播放 久久久入口 | v片在线看| 国产一区二区三区在线免费 | 欧美一区二区三区中文字幕 | 国产1级视频 | 91九色视频观看 | 成人午夜免费网站 | 高清做爰免费无遮网站挡 | 一级性生活视频 | 午夜视频色 | 毛片在线免费观看完整版 | 国产成人在线看 | 最近日本电影hd免费观看 | 国产午夜免费福利 | av电影网站在线 | 久久成人免费观看 | 欧美大荫蒂xxx | 亚洲第一成人av | 天天草天天操 | 中文在线日韩 | 成年人观看免费视频 | 毛片大全 |