一宋列、位運算
-
&
:按位與辆布,可以用來取出特定位的值瞬矩。需要取哪一位,就將哪一位置為0锋玲。掩碼景用,一般是用來按位與運算。0011 &0010 ------ 0010
-
|
:按位或惭蹂,可以用來設(shè)置某一位的值伞插。需要設(shè)置哪一位,就將哪一位置為1剿干。0001 |0010 ------ 0011
~
:按位取反#define MJRichMask (1<<1)
蜂怎,代表左移一位-
使用位域
struct { char tall : 1; // 只使用1位,默認(rèn)開始是最右邊一位 char rich : 1; char handsome : 1; } tallRichHandsome;
二置尔、isa
-
變化
- 在arm64架構(gòu)之前杠步,isa就是一個普通的指針,存儲著Class榜轿、Meta-Class對象的內(nèi)存地址
- 從arm64架構(gòu)開始幽歼,對isa進行了優(yōu)化,變成了一個共用體(union)結(jié)構(gòu)谬盐,使用位域來存儲更多的信息
union isa_t { isa_t() { } isa_t(uintptr_t value) : bits(value) { } Class cls; uintptr_t bits; #if defined(ISA_BITFIELD) struct { ISA_BITFIELD; // defined in isa.h }; #endif }; # 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 deallocating : 1; \ uintptr_t has_sidetable_rc : 1; \ uintptr_t extra_rc : 19
-
isa位域詳解
nonpointer
0甸私,代表普通指針,存儲著Class飞傀、Meta-Class對象的內(nèi)存地址
1皇型,代表優(yōu)化過诬烹,使用位域存儲更多的信息has_assoc
是否設(shè)置過關(guān)聯(lián)對象,如果沒有弃鸦,釋放時會更快
has_cxx_dtor
是否有c++的析構(gòu)函數(shù)(.cxx_destruct)绞吁,如果沒有,釋放時會更快
shiftcls
存儲著Class唬格、Meta-Class對象的內(nèi)存地址信息
magic
用于在調(diào)試時分辨對象是否未完成初始化
weakly_referenced
是否有被弱引用指向過家破,如果沒有,釋放時會更快
deallocating
對象是否正在釋放
has_sidetable_rc
引用計數(shù)器是否過大無法存儲在isa中
如果為1购岗,那么引用計數(shù)會存儲在一個叫SideTable的類的屬性中extra_rc
里面存儲的值是引用計數(shù)器減1
三汰聋、Class
-
Class結(jié)構(gòu)
image.png -
class_rw_t
-
class_rw_t
里邊的methods、properties喊积、protocols都是二維數(shù)組烹困,是可讀可寫的,包含了類的初始內(nèi)容注服,分類的內(nèi)容
image.png
-
-
class_ro_t
-
class_ro_t
里面的baseMethodList韭邓、baseProtocols、ivars溶弟、baseProperties都是一維數(shù)組女淑,是只讀的,包含了類的初始內(nèi)容
image.png
-
-
method_t
-
method_t
是對方法/函數(shù)的封裝
struct method_t { SEL name; // 函數(shù)名 const char *types; // 編碼(返回值類型辜御、參數(shù)類型) MethodListIMP imp; // 函數(shù)指針(函數(shù)地址) struct SortBySELAddress : public std::binary_function<const method_t&, const method_t&, bool> { bool operator() (const method_t& lhs, const method_t& rhs) { return lhs.name < rhs.name; } }; };
-
IMP
代表函數(shù)的具體實現(xiàn)
typedef id _Nullable (*IMP)(id _Nonnull, SEL _Nonnull, ...);
-
SEL
代表方法名/函數(shù)名鸭你,一般叫做選擇器,底層結(jié)構(gòu)跟char *
類似
* 可以通過@selector()
和sel_registerName()
獲得
* 可以通過sel_getName()
和NSStringFromSelector()
轉(zhuǎn)成字符串
* 不同類中相同名字的方法擒权,所對應(yīng)的方法選擇器是相同的
typedef struct objc_selector *SEL;
-
types
包含了函數(shù)返回值袱巨、參數(shù)編碼的字符串
image.png - Type Encoding
- iOS中提供了一個叫做
@encode
指令,可以將具體類型表示成字符串編碼
image.png
- iOS中提供了一個叫做
-
四碳抄、方法緩存
-
Class內(nèi)部結(jié)構(gòu)中有個方法緩存(cache_t),用散列表(哈希表)來緩存曾經(jīng)調(diào)用過的方法愉老,可以提高方法的查找速度(以空間換時間)
-
緩存查找
五、objc_msgSend()
-
執(zhí)行流程
- OC中的方法剖效,其實都是轉(zhuǎn)換為objc_msgSend函數(shù)的調(diào)用
- objc_msgSend的執(zhí)行流程可以分為3大階段
- 消息發(fā)送
- 動態(tài)方法解析
- 消息轉(zhuǎn)發(fā)
-
objc_msgSend的源碼跟讀
-
消息發(fā)送流程
- receiver通過isa指針找到receiverClass
- receiverClass通過superclass指針找到superClass
- 如果是從class_rw_t中查找方法
- 已經(jīng)排序的嫉入,二分查找
- 沒有排序的,遍歷查找
-
動態(tài)方法解析流程
- 可以實現(xiàn)以下方法璧尸,動態(tài)添加方法實現(xiàn)
+resolveInstanceMethod
+resolveClassMethod
- 動態(tài)解析過后咒林,會重新走“消息發(fā)送”流程
- “從receiverClass的cache中查找方法”這一步開始執(zhí)行
- 動態(tài)方法解析例子
- Method可以等價理解為
struct method_t *
- Method可以等價理解為
- 補充:
@dynamic
告訴編譯器不用自動生成getter
和setter
,不用自動生成成員變量爷光,等到運行時再添加方法實現(xiàn)
- 可以實現(xiàn)以下方法璧尸,動態(tài)添加方法實現(xiàn)
-
消息轉(zhuǎn)發(fā)流程
- 開發(fā)者可以在
forwardInvocation
方法中自定義任何邏輯 - 以上方法都有對象方法垫竞、類方法兩種實現(xiàn)
-
NSMethodSignature
的生成例子
- 開發(fā)者可以在
六、super
-
[super message]
的底層實現(xiàn)- 消息接受者仍然是子類對象
- 從父類開始查找方法的實現(xiàn)
-
使用clang轉(zhuǎn)化的c++代碼蛀序,不一定是程序最終生成的代碼欢瞪。super的調(diào)用活烙,底層其實是轉(zhuǎn)換為
objc_msgSendSuper2
函數(shù)的調(diào)用,接受兩個參數(shù)struct objc_super2
- SEL
struct objc_super2 { id receiver; // 消息接受者 Class current_class; // receiver的Class對象 };
七遣鼓、LLVM的中間代碼(IR)
- Objective-C在變?yōu)闄C器代碼之前瓣颅,會被LLVM編譯器轉(zhuǎn)換為中間代碼(Intermediate Representation)
- 可以使用以下命令行指令生成中間代碼
clang -emit-llvm -S main.m
- 語法簡介
- 具體可以參考官方文檔:https://llvm.org/docs/LangRef.html
八、Runtime API
- 類
- 動態(tài)創(chuàng)建一個類(參數(shù):父類譬正,類名,額外的內(nèi)存空間)
Class _Nullable objc_allocateClassPair(Class _Nullable superclass, const char * _Nonnull name, size_t extraBytes)
- 注冊一個類(需要在類注冊之前添加成員變量)
void objc_registerClassPair(Class _Nonnull cls)
- 銷毀一個類
void objc_disposeClassPair(Class _Nonnull cls)
- 獲取isa指向的Class
Class object_getClass(id obj)
- 設(shè)置isa指向的Class
Class object_setClass(id obj, Class cls)
- 判斷一個OC對象是否為Class
BOOL object_isClass(id obj)
- 判斷一個Class是否為元類
BOOL class_isMetaClass(Class cls)
- 獲取父類
Class class_getSuperclass(Class cls)
- 動態(tài)創(chuàng)建一個類(參數(shù):父類譬正,類名,額外的內(nèi)存空間)
- 成員變量
- 獲取一個實例變量信息
Ivar class_getInstanceVariable(Class cls, const char * name)
- 拷貝示例變量列表(最后需要調(diào)用free釋放)
Ivar *class_copyIvarList(Class cls,unsigned int *outCount)
- 設(shè)置和獲取成員變量的值
void object_setIvar(id obj, Ivar ivar, id value)
id object_getIvar(id obj, Ivar ivar)
- 動態(tài)添加成員變量(已經(jīng)注冊的類不能動態(tài)添加成員變量)
BOOL class_addIvar(Class cls, const char * name, size_t size, uint8_t alignment, const char * types)
- 獲取成員變量的相關(guān)信息
const char *ivar_getName(Ivar v)
const char *ivar_getTypeEncoding(Ivar v)
- 獲取一個實例變量信息
- 屬性
- 獲取一個屬性
objc_property_t _Nullable class_getProperty(Class _Nullable cls, const char * _Nonnull name)
- 拷貝屬性列表(需要調(diào)用free釋放)
objc_property_t _Nonnull * _Nullable class_copyPropertyList(Class _Nullable cls, unsigned int * _Nullable outCount)
- 動態(tài)添加屬性
BOOL class_addProperty(Class _Nullable cls, const char * _Nonnull name, const objc_property_attribute_t * _Nullable attributes, unsigned int attributeCount)
- 動態(tài)替換屬性
void class_replaceProperty(Class _Nullable cls, const char * _Nonnull name, const objc_property_attribute_t * _Nullable attributes, unsigned int attributeCount)
- 獲取屬性的一些信息
const char * _Nonnull property_getName(objc_property_t _Nonnull property)
const char * _Nullable property_getAttributes(objc_property_t _Nonnull property)
- 獲取一個屬性
- 方法
- 獲得一個實例方法檬姥、類方法
Method _Nullable class_getInstanceMethod(Class _Nullable cls, SEL _Nonnull name)
Method _Nullable class_getClassMethod(Class _Nullable cls, SEL _Nonnull name)
- 方法實現(xiàn)相關(guān)操作
IMP _Nullable class_getMethodImplementation(Class _Nullable cls, SEL _Nonnull name)
IMP _Nonnull method_setImplementation(Method _Nonnull m, IMP _Nonnull imp)
void method_exchangeImplementations(Method _Nonnull m1, Method _Nonnull m2)
- 拷貝方法列表(需要調(diào)用free函數(shù)釋放)
Method _Nonnull * _Nullable class_copyMethodList(Class _Nullable cls, unsigned int * _Nullable outCount)
- 動態(tài)添加方法
BOOL class_addMethod(Class _Nullable cls, SEL _Nonnull name, IMP _Nonnull imp, const char * _Nullable types)
- 動態(tài)替換方法
IMP _Nullable class_replaceMethod(Class _Nullable cls, SEL _Nonnull name, IMP _Nonnull imp, const char * _Nullable types)
- 獲取方法的相關(guān)信息(帶有copy的需要調(diào)用free釋放)
SEL _Nonnull method_getName(Method _Nonnull m)
IMP _Nonnull method_getImplementation(Method _Nonnull m)
const char * _Nullable method_getTypeEncoding(Method _Nonnull m)
unsigned int method_getNumberOfArguments(Method _Nonnull m)
char * _Nonnull method_copyReturnType(Method _Nonnull m)
char * _Nullable method_copyArgumentType(Method _Nonnull m, unsigned int index)
- 選擇器相關(guān)
const char * _Nonnull sel_getName(SEL _Nonnull sel)
SEL _Nonnull sel_registerName(const char * _Nonnull str)
- 用block作為方法實現(xiàn)
IMP _Nonnull imp_implementationWithBlock(id _Nonnull block)
id _Nullable imp_getBlock(IMP _Nonnull anImp)
BOOL imp_removeBlock(IMP _Nonnull anImp)
- 獲得一個實例方法檬姥、類方法