oc是面向?qū)ο蟮恼Z言理郑。對象可以看做我們對底層數(shù)據(jù)的抽象封裝。對象有自己的成員變量咨油,具備一些功能您炉,有自己所屬的類,甚至有父類役电,子類赚爵。那么oc的面相對象是怎么設計,怎么實現(xiàn)的?它的底層是由什么樣的數(shù)據(jù)結構支持的呢冀膝?
編譯
把OC編譯成c/c++是我們了解OC底層實現(xiàn)的一種方式唁奢。
簡單的clang編譯
clang -rewrite-objc main.m -o main.cpp
有時候clang編譯會需要一些環(huán)境,sdk支持窝剖,動態(tài)特性支持
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
xcrun命令 xcode自帶的命令行工具麻掸,在clang基礎上進行了一些封裝,編譯oc代碼赐纱,更簡便一些
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 (?機)
gcc編譯器在xcode的早期版本中使用脊奋,xcode現(xiàn)在的編譯器是LLVM,采用三項插拔式設計。LLVM設計的最重要方面是疙描,使用通用代碼表示形式(IR)诚隙,它是用來在編譯器中表示代碼的形式。所以LLVM可以以任何編程語言獨立編寫前端起胰,并且可以為任意硬件架構獨立編寫后端久又。
clang 是LLVM一個子項目。負責編譯c/c++/Objective-c效五。
cpp文件中的對象
LGPerson
typedef struct objc_object LGPerson;
typedef struct {} _objc_exc_LGPerson;
#endif
struct LGPerson_IMPL {
struct NSObject_IMPL NSObject_IVARS;
NSString *hobby;
};
本質(zhì)是一個objc_object類型的結構體籽孙。
objc_object
struct objc_object {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
};
Class
typedef struct objc_class *Class;
objc_class
objc_class : objc_object {---}
id
typedef struct objc_object *id;
根據(jù)已有信息畫個圖
總結下已有信息
- 對象本質(zhì)是一個objc_object類型的結構體
- 對象都有一個指向objc_class結構體的指針isa
- objc_class結構體也有一個指向objc_class的指針isa
- id類型是objc_object *
難道我們isa指向會無限循環(huán)下嗎,如果不會那對象objc_object 和objc_class他們之間的結構是怎么樣的呢火俄?
無論如何,我們可以看到isa指針在期中扮演這關鍵的角色
isa
objc源碼
union isa_t {
isa_t() { }
isa_t(uintptr_t value) : bits(value) { }
uintptr_t bits;
private:
// Accessing the class requires custom ptrauth operations, so
// force clients to go through setClass/getClass by making this
// private.
Class cls;
public:
#if defined(ISA_BITFIELD)
struct {
ISA_BITFIELD; // defined in isa.h
};
bool isDeallocating() {
return extra_rc == 0 && has_sidetable_rc == 0;
}
void setDeallocating() {
extra_rc = 0;
has_sidetable_rc = 0;
}
#endif
void setClass(Class cls, objc_object *obj);
Class getClass(bool authenticated);
Class getDecodedClass(bool authenticated);
};
如果是64位系統(tǒng)讲冠,isa_t是聯(lián)合體位域瓜客,現(xiàn)在iOS手機基本都是arm64架構。
ISA_BITFIELD是對位域的定義
x86_64
# elif __x86_64__
# define ISA_MASK 0x00007ffffffffff8ULL
# define ISA_MAGIC_MASK 0x001f800000000001ULL
# define ISA_MAGIC_VALUE 0x001d800000000001ULL
# define ISA_HAS_CXX_DTOR_BIT 1
# define ISA_BITFIELD \
uintptr_t nonpointer : 1; //是否是nonpointer \
uintptr_t has_assoc : 1; //是否有關聯(lián)對象 \
uintptr_t has_cxx_dtor : 1; //是否有cxx析構函數(shù) \
uintptr_t shiftcls : 44; /*MACH_VM_MAX_ADDRESS 0x7fffffe00000*/ \
uintptr_t magic : 6; //是否已完成初始化 \
uintptr_t weakly_referenced : 1; //是否被弱引用 \
uintptr_t unused : 1; //是否正在被釋放 \
uintptr_t has_sidetable_rc : 1; //引用計數(shù)是否存在sideTable中 \
uintptr_t extra_rc : 8 //存儲該對象的引用計數(shù)值減一后的結果, 如果夠存則存在這里竿开,不夠則存在 sidetable
arm64
# if __arm64__
// ARM64 simulators have a larger address space, so use the ARM64e
// scheme even when simulators build for ARM64-not-e.
# if __has_feature(ptrauth_calls) || TARGET_OS_SIMULATOR
# define ISA_MASK 0x007ffffffffffff8ULL
# define ISA_MAGIC_MASK 0x0000000000000001ULL
# define ISA_MAGIC_VALUE 0x0000000000000001ULL
# define ISA_HAS_CXX_DTOR_BIT 0
# define ISA_BITFIELD \
uintptr_t nonpointer : 1; \
uintptr_t has_assoc : 1; \
uintptr_t weakly_referenced : 1; \
uintptr_t shiftcls_and_sig : 52; \
uintptr_t has_sidetable_rc : 1; \
uintptr_t extra_rc : 8
# define RC_ONE (1ULL<<56)
# define RC_HALF (1ULL<<7)
# else
# define ISA_MASK 0x0000000ffffffff8ULL
# define ISA_MAGIC_MASK 0x000003f000000001ULL
# define ISA_MAGIC_VALUE 0x000001a000000001ULL
# define ISA_HAS_CXX_DTOR_BIT 1
# define ISA_BITFIELD \
uintptr_t nonpointer : 1; \
uintptr_t has_assoc : 1; \
uintptr_t has_cxx_dtor : 1; \
uintptr_t shiftcls : 33; /*MACH_VM_MAX_ADDRESS 0x1000000000*/ \
uintptr_t magic : 6; // \
uintptr_t weakly_referenced : 1; \
uintptr_t unused : 1; \
uintptr_t has_sidetable_rc : 1; \
uintptr_t extra_rc : 19
# define RC_ONE (1ULL<<45)
# define RC_HALF (1ULL<<18)
位域提供了一種手段谱仪,使得可在高級語言中實現(xiàn)數(shù)據(jù)的壓縮,節(jié)省了存儲空間否彩,同時也提高了程序的效率疯攒。
上面我們isa是一個objc_class的指針。位域是我們充分利用了指針64位的內(nèi)存空間列荔,不進存儲了objc_class的指著地址敬尺,還存楚了其他對象的相關信息。
總結:
- 對象本質(zhì)是一個objc_object類型的結構體
- 對象都有一個指向objc_class結構體的指針isa
- objc_class結構體也有一個指向objc_class的指針isa
- id類型是objc_object *
- isa是一個聯(lián)合體位域贴浙,不僅存儲了objc_class地址砂吞,還存儲了對象的其他相關信息。
- 聯(lián)合體位域的使用崎溃,優(yōu)化了內(nèi)存也提高了部分信息的查詢效率蜻直。