欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

深入理解Objective-C中類的數(shù)據(jù)結(jié)構(gòu)

 更新時(shí)間:2018年05月15日 09:46:46   作者:CoderHG  
最近發(fā)現(xiàn)用Objective-C確實(shí)好容易,下面這篇文章主要給大家介紹了關(guān)于Objective-C中類的數(shù)據(jù)結(jié)構(gòu)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

一、類的結(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)單的編寫如下代碼:

// CustomFile.m
#import <Foundation/Foundation.h>
void 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)都是可以的。

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

struct NSObject_IMPL {
 Class isa;
};

其中 Class 的定義如下:

typedef struct objc_class *Class;

再來(lái)看一下在實(shí)際中的 NSObject 類的聲明是什么樣的:

@interface NSObject <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 類。代碼編寫如下:

// Person.m
#import <Foundation/Foundation.h>

// 類的申明
@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 都繼承過來(lái)了。

似乎明白了一個(gè)套路

在 NSObject 中只有一個(gè) Class 類型的成員變量 isa,在沒有自定義任何的成員屬性的情況下,繼承的子類中的 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 文件,編寫代碼如下:

// FunClass.m
#import <Foundation/Foundation.h>

// 類的申明
@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)沒有任何的改變,是這樣的:

struct FunClass_IMPL {
 struct NSObject_IMPL NSObject_IVARS;
};

但是我們會(huì)發(fā)現(xiàn)另外一個(gè)問題,在 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)體。編寫的代碼如下:

// ==== 類的定義部分 ====
// 類的申明
@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
 }
}

通過結(jié)構(gòu)體指針能打印出在類對(duì)象中設(shè)置的值,說(shuō)明在 類轉(zhuǎn)結(jié)構(gòu)體的過程是有效的。

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 解開多年來(lái)的誤解 的慘痛教訓(xùn),所以對(duì)遇到的 crash 就會(huì)很敏感。看一下上面的這張圖,有一個(gè)關(guān)鍵的點(diǎn)是不可以忽視的,就是這里的值:


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

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

所以在第一個(gè)實(shí)驗(yàn)中的 類轉(zhuǎn)結(jié)構(gòu)體 中是有效的,也許是一個(gè)偶然。畢竟我們?cè)谏厦娴?.cpp 文件中查看數(shù)據(jù)結(jié)構(gòu)的時(shí)候也只是看了一個(gè)大概,并沒有看全部的。

OK,忘記本節(jié)(自定義一個(gè) Class 與對(duì)應(yīng)的結(jié)構(gòu)體)中遇到的不愉快, 至少 類轉(zhuǎn)結(jié)構(gòu)體 是有效的,也能說(shuō)明一些問題。

本系列的文章,有:

1、Objective-C 中類的數(shù)據(jù)結(jié)構(gòu)

2、Objective-C 中實(shí)例所占內(nèi)存的大小

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對(duì)腳本之家的支持。

相關(guān)文章

  • iOS判斷網(wǎng)絡(luò)請(qǐng)求超時(shí)的方法

    iOS判斷網(wǎng)絡(luò)請(qǐng)求超時(shí)的方法

    本篇文章主要介紹了iOS判斷網(wǎng)絡(luò)請(qǐng)求超時(shí)的方法,現(xiàn)在分享給大家,也給大家做個(gè)參考。感興趣的小伙伴們可以參考一下。
    2016-12-12
  • 簡(jiǎn)單好用的iOS導(dǎo)航欄封裝.runtime屬性控制實(shí)例代碼

    簡(jiǎn)單好用的iOS導(dǎo)航欄封裝.runtime屬性控制實(shí)例代碼

    這篇文章主要給大家介紹了簡(jiǎn)單好用的iOS導(dǎo)航欄封裝.runtime屬性控制的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-10-10
  • iOS中修改UISearchBar圓角的小技巧分享

    iOS中修改UISearchBar圓角的小技巧分享

    UISearchBar也是iOS開發(fā)常用控件之一,點(diǎn)進(jìn)去看看里面的屬性barStyle、text、placeholder等等。下面這篇文章主要給大家分享了iOS中修改UISearchBar圓角的小技巧,文中給出了詳細(xì)的示例代碼供大家參考學(xué)習(xí),需要的朋友們下面來(lái)一起看看吧。
    2017-05-05
  • iOS自帶原生二維碼掃描的實(shí)現(xiàn)

    iOS自帶原生二維碼掃描的實(shí)現(xiàn)

    最近項(xiàng)目中需要做一個(gè)二維碼掃描,雖然有很多二維碼掃描的第三方可以用,但是考慮到項(xiàng)目中的需要,所以我放棄了使用三方庫(kù),而采用了蘋果原生的掃描。下面這篇文章就介紹了iOS自帶原生二維碼掃描的實(shí)現(xiàn),需要的朋友可以參考借鑒,下面來(lái)一起看看吧。
    2017-01-01
  • IOS 改變鍵盤顏色代碼

    IOS 改變鍵盤顏色代碼

    這篇文章主要介紹了IOS 改變鍵盤顏色代碼,十分的簡(jiǎn)單實(shí)用,有需要的小伙伴可以參考下。
    2015-05-05
  • objc方法聲明和實(shí)現(xiàn)由于參數(shù)類型不一致所引發(fā)的崩潰

    objc方法聲明和實(shí)現(xiàn)由于參數(shù)類型不一致所引發(fā)的崩潰

    這篇文章主要為大家介紹了objc方法聲明和實(shí)現(xiàn)由于參數(shù)類型不一致所引發(fā)的崩潰詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • IOS 禁止縮放頁(yè)面的實(shí)現(xiàn)方法

    IOS 禁止縮放頁(yè)面的實(shí)現(xiàn)方法

    這篇文章主要介紹了IOS 禁止縮放頁(yè)面的實(shí)現(xiàn)方法的相關(guān)資料,這里主要介紹了IOS 10如何通過設(shè)置來(lái)實(shí)現(xiàn)禁止縮放及實(shí)現(xiàn)方法,需要的朋友可以參考下
    2017-07-07
  • iOS無(wú)障礙適配西瓜視頻Voice?Over實(shí)踐示例

    iOS無(wú)障礙適配西瓜視頻Voice?Over實(shí)踐示例

    本文從研發(fā)的視角出發(fā),講述了如何使用?Voice?Over、如何適配?Voice?Over?以及適配過程中如果遇到問題應(yīng)該如何解決。希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-05-05
  • IOS網(wǎng)絡(luò)請(qǐng)求之NSURLSession使用詳解

    IOS網(wǎng)絡(luò)請(qǐng)求之NSURLSession使用詳解

    這篇文章主要介紹了IOS網(wǎng)絡(luò)請(qǐng)求之NSURLSession使用詳解,今天使用NSURLConnection分別實(shí)現(xiàn)了get、post、表單提交、文件上傳、文件下載,有興趣的可以了解一下。
    2017-02-02
  • 舉例講解設(shè)計(jì)模式中的原型模式在iOS應(yīng)用開發(fā)中的作用

    舉例講解設(shè)計(jì)模式中的原型模式在iOS應(yīng)用開發(fā)中的作用

    這篇文章主要介紹了設(shè)計(jì)模式中的原型模式在iOS應(yīng)用開發(fā)中的作用,示例代碼為傳統(tǒng)的Objective-C,需要的朋友可以參考下
    2016-04-04

最新評(píng)論