OC底層3-對(duì)象的本質(zhì)及其擴(kuò)展、nonPointerIsa的分析

1、對(duì)象的本質(zhì)及其擴(kuò)展

1.1什么是clang?

在探索對(duì)象本質(zhì)之前,我們先來(lái)學(xué)習(xí)一下:
Clang是?個(gè)C語(yǔ)?、C++、Objective-C語(yǔ)?的輕量級(jí)編譯器。源代碼發(fā)布于BSD協(xié)議下。Clang將?持其普通lambda表達(dá)式、返回類型的簡(jiǎn)化處理以及更好的處理constexpr關(guān)鍵字。簡(jiǎn)單理解Clang是?個(gè)由Apple主導(dǎo)編寫(xiě),基于LLVMC/C++/Objective-C編譯器。

1.2 clang常使用技巧?

1.clang -rewrite-objc main.m -o main.cpp 把?標(biāo)?件編譯成c++?件
舉個(gè)??:
-打開(kāi)項(xiàng)目工程

截屏2021-06-16 上午1.01.04.png

截屏2021-06-16 上午1.03.44.png

截屏2021-06-16 上午1.05.15.png
截屏2021-06-16 上午1.02.17.png

此時(shí),我們就獲取到了main.m 目錄下就獲取到對(duì)應(yīng)main.cpp源文件
接下來(lái)有個(gè)東西要注意的是,把?標(biāo)?件編譯成c++?件可能會(huì)碰到UIKit報(bào)錯(cuò)問(wèn)題,可以用如下命令進(jìn)行解決,其中需要更改相應(yīng)的版本號(hào):
clang -rewrite-objc -fobjc-arc -fobjc-runtime=ios-13.0.0 -isysroot /
Applications/Xcode.app/Contents/Developer/Platforms/
iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator13.0.sdk main.m

因?yàn)?strong>xcode安裝的時(shí)候順帶安裝了xcrun命令,xcrun命令在clang的基礎(chǔ)上進(jìn)?了?些封裝,要更好??些,可以用如下方法進(jìn)行編譯:

xcrun -sdk iphonesimulator clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp(模擬器)

xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp(?機(jī))

1.3 通過(guò)main.cpp源文件的源碼我們可以進(jìn)一步分析,對(duì)象的本質(zhì)

1.3.1首先,先看先main.m的代碼


#import <Foundation/Foundation.h>
#import <objc/runtime.h>

// 對(duì)象在底層的本質(zhì)就是結(jié)構(gòu)體
@interface LGPerson : NSObject
@property (nonatomic, strong) NSString *KCName;

@end

@implementation LGPerson

@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        NSLog(@"Hello, World!");
    }
    return 0;
}

1.3.2.在大打開(kāi)看先main.cpp的代碼,一個(gè)main的源碼有十幾萬(wàn)行,一下子暈頭轉(zhuǎn)向,這怎么看:


截屏2021-06-16 上午1.25.32.png

全局搜索下LGPerson:

#ifndef _REWRITER_typedef_LGPerson
#define _REWRITER_typedef_LGPerson
typedef struct objc_object LGPerson;
typedef struct {} _objc_exc_LGPerson;
#endif

extern "C" unsigned long OBJC_IVAR_$_LGPerson$_KCName;
struct LGPerson_IMPL {
    struct NSObject_IMPL NSObject_IVARS;
    NSString *_KCName;
};

// @property (nonatomic, strong) NSString *KCName;

/* @end */


// @implementation LGPerson


static NSString * _I_LGPerson_KCName(LGPerson * self, SEL _cmd) { return (*(NSString **)((char *)self + OBJC_IVAR_$_LGPerson$_KCName)); }
static void _I_LGPerson_setKCName_(LGPerson * self, SEL _cmd, NSString *KCName) { (*(NSString **)((char *)self + OBJC_IVAR_$_LGPerson$_KCName)) = KCName; }
// @end

int main(int argc, const char * argv[]) {
    /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; 

        NSLog((NSString *)&__NSConstantStringImpl__var_folders_7l_wm83md7d5w3f9csj6_7_tlrh0000gn_T_main_07314a_mi_0);
    }
    return 0;
}

繼續(xù)探索看看:typedef struct objc_object LGPerson; 得到 objc_object源碼,是一個(gè)結(jié)構(gòu)體

struct objc_object {
    Class _Nonnull isa __attribute__((deprecated));
};
struct LGPerson_IMPL {
    struct NSObject_IMPL NSObject_IVARS;
    NSString *_KCName;
};

LGPerson_IMPL 包含了我們定義的成員變量_KCName, 還有一個(gè)結(jié)構(gòu)體struct NSObject_IMPL NSObject_IVARS;
繼續(xù)往下查看NSObject_IMPL

struct NSObject_IMPL {
    Class isa;
};

在看看:Class

typedef struct objc_class *Class;
struct objc_class {
    Class _Nonnull isa __attribute__((deprecated));
} __attribute__((unavailable));

總結(jié):Class 的本質(zhì) 是一個(gè)objc_class 類型,意味著當(dāng)前的Class是一個(gè)結(jié)構(gòu)體指針, Class此時(shí)充當(dāng)只是一個(gè)別名而已,一步步查看源碼下來(lái):對(duì)象在底層的本質(zhì)就是結(jié)構(gòu)體 。
同時(shí):平時(shí)我們定義id Person 為什么沒(méi)有帶* 號(hào),通過(guò)底層代碼可以發(fā)現(xiàn) id 的本質(zhì) 是一個(gè)objc_object* 類型,意味著當(dāng)前的id是一個(gè)結(jié)構(gòu)體指針, id此時(shí)充當(dāng)只是一個(gè)別名而已。

typedef struct objc_object *id;
1.4 get 與set 方法的擴(kuò)展分析:

以_KCName為例:
//當(dāng)前的隱藏參數(shù)

static NSString * _I_LGPerson_KCName(LGPerson * self, SEL _cmd) { return (*(NSString **)((char *)self + OBJC_IVAR_$_LGPerson$_KCName)); }

//set方法
//存值的地方

static void _I_LGPerson_setKCName_(LGPerson * self, SEL _cmd, NSString *KCName) { (*(NSString **)((char *)self + OBJC_IVAR_$_LGPerson$_KCName)) = KCName; }

所有的對(duì)象都在當(dāng)前的堆區(qū),開(kāi)辟內(nèi)存空間,那么內(nèi)存空間里面裝什么呢?裝成員變量,第一個(gè)成員變量裝的是什么,是isa?如何獲取,可以通過(guò)控制臺(tái)x/4g 去獲取

所有的內(nèi)存,首先是怎么訪問(wèn)的?
首先第一點(diǎn)拿到內(nèi)存的地址,以LGPerson為例,首先要拿到LGPerson的首地址,之后在進(jìn)行OBJC_IVAR量的平移,拿到KCName對(duì)應(yīng)地址,從而獲取地址里面KCName的值,所以說(shuō)KCName的值不是天然存在的。
這就是為什么說(shuō)get方法 return (*(NSString **)((char *)self + OBJC_IVAR__LGPerson_KCName))的原因。

2、nonPointerIsa的分析:

文章未完成,接下來(lái)繼續(xù)分析nonPointerIsa

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容