深刻淺出 Runtime(一):初識

Runtime 系列文章

深刻淺出 Runtime(一):初識
深刻淺出 Runtime(二):數據結構
深刻淺出 Runtime(三):消息機制
深刻淺出 Runtime(四):super 的本質
深刻淺出 Runtime(五):具體應用
深刻淺出 Runtime(六):相關面試題git

Runtime 簡介

  • Runtime 是一個用C、彙編編寫的運行時庫,包含了不少 C 語言的 API,封裝了不少動態性相關的函數;
  • Objective-C 是一門動態運行時語言,容許不少操做推遲到程序運行時再進行。OC的動態性就是由 Runtime 來支撐和實現的,Rumtime 就是它的核心;
  • 咱們平時編寫的OC代碼,底層都是轉換成了 Runtime API 進行調用。

Objective-C 是一門動態運行時語言

什麼是編譯時與運行時?

  • 編譯時:編譯器將程序代碼編譯成計算機可以識別的語言,只進行一些簡單的語法檢查;
  • 運行時:代碼跑起來,被裝載到內存中去,此時若是出錯會致使程序崩潰。如經典的 crash:unrecognized selector send to instance/class

編譯時語言與動態運行時語言的區別?

  • 編譯時語言:在編譯期進行函數決議;
  • 動態運行時語言:將函數決議推遲到運行時。
舉例

對於 NSString *string = [[NSMutableArray alloc]init];github

  • 編譯時:編譯器進行類型檢查的時候,因爲給一個NSString類型的指針賦值的是一個NSMutableArray對象,因此編譯器會給出類型不匹配的警告。可是編譯器會將 string看成NSString的實例,因此string對象調用NSString的方法,編譯沒有任何問題,而調用NSMutableArray的方法,編譯會直接報錯。
  • 運行時:因爲string其實是指向一個NSMutableArray對象,NSMutableArray對象沒有stringByAppendingString:方法,因此致使crash:unrecognized selector send to instance
NSString *string = [[NSMutableArray alloc]init];  //⚠️Incompatible pointer types initializing 'NSString *' with an expression of type 'NSMutableArray *'
    [string stringByAppendingString:@"abc"];
    [string addObject:@"abc"];  //❌No visible @interface For 'NSString' declares the selector 'addObject:'
複製代碼

Runtime 有兩個版本

  • Legacy (早期版本) ,對應的編程接口:Objective-C 1.0,應用於32-bit programs on OS X desktop
  • Modern (現代版本),對應的編程接口:Objective-C 2.0,應用於iPhone applications and 64-bit programs on OS X v10.5 and later

Objective-C 程序在三個不一樣的級別上與 Runtime 系統進行交互

  • 經過 Objective-C 源代碼;
  • 經過 Foundation 框架中 NSObject 類定義的方法,如:
// 根據 instance 對象或者類名得到一個 class 對象
- (Class)class
+ (Class)class
// 判斷當前 instance/class 對象的 isa 指向是否是 class/meta-class 對象或者它的子類類型
- (BOOL)isKindOfClass:(Class)cls
+ (BOOL)isKindOfClass:(Class)cls
// 判斷當前 instance/class 對象的 isa 指向是否是 class/meta-class 對象類型
- (BOOL)isMemberOfClass:(Class)cls
+ (BOOL)isMemberOfClass:(Class)cls
// 判斷對象是否能夠接收特定消息
- (BOOL)respondsToSelector:(SEL)sel
+ (BOOL)respondsToSelector:(SEL)sel
// 判斷對象是否實現了特定協議中定義的方法
- (BOOL)conformsToProtocol:(Protocol *)protocol
+ (BOOL)conformsToProtocol:(Protocol *)protocol
// 能夠根據一個 SEL,獲得該方法的 IMP
- (IMP)methodForSelector:(SEL)sel
+ (IMP)methodForSelector:(SEL)sel
複製代碼

類相關面試

// 動態建立一對類和元類(參數:父類,類名,額外的內存空間)
Class objc_allocateClassPair(Class superclass, const char *name, size_t extraBytes)
// 註冊一對類和元類(要在類註冊以前添加成員變量)
void objc_registerClassPair(Class cls) 
// 銷燬一對類和元類
void objc_disposeClassPair(Class cls)
// 獲取 isa 指向的 Class
Class object_getClass(id obj)
// 設置 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)
複製代碼

成員變量相關objective-c

// 獲取一個實例變量信息
Ivar class_getInstanceVariable(Class cls, const char *name)
// 拷貝實例變量列表(最後須要調用 free 釋放)
Ivar *class_copyIvarList(Class cls, unsigned int *outCount)
// 設置和獲取成員變量的值
void object_setIvar(id obj, Ivar ivar, id value)
id object_getIvar(id obj, Ivar ivar)
// 動態添加成員變量(已經註冊的類是不能動態添加成員變量的)
BOOL class_addIvar(Class cls, const char * name, size_t size, uint8_t alignment, const char * types)
// 獲取成員變量的相關信息
const char *ivar_getName(Ivar v)
const char *ivar_getTypeEncoding(Ivar v)
複製代碼

屬性相關express

// 獲取一個屬性
objc_property_t class_getProperty(Class cls, const char *name)
// 拷貝屬性列表(最後須要調用 free 釋放)
objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount)
// 動態添加屬性
BOOL class_addProperty(Class cls, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount)
// 動態替換屬性
void class_replaceProperty(Class cls, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount)
// 獲取屬性的一些信息
const char *property_getName(objc_property_t property)
const char *property_getAttributes(objc_property_t property)
複製代碼

方法相關編程

// 得到一個實例方法、類方法
Method class_getInstanceMethod(Class cls, SEL name)
Method class_getClassMethod(Class cls, SEL name)
// 方法實現相關操做
IMP class_getMethodImplementation(Class cls, SEL name) 
IMP method_setImplementation(Method m, IMP imp)
void method_exchangeImplementations(Method m1, Method m2) 
// 拷貝方法列表(最後須要調用 free 釋放)
Method *class_copyMethodList(Class cls, unsigned int *outCount)
// 動態添加方法
BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)
// 動態替換方法
IMP class_replaceMethod(Class cls, SEL name, IMP imp, const char *types)
// 獲取方法的相關信息(帶有 copy 的須要調用 free 去釋放)
SEL method_getName(Method m)
IMP method_getImplementation(Method m)
const char *method_getTypeEncoding(Method m)
unsigned int method_getNumberOfArguments(Method m)
char *method_copyReturnType(Method m)
char *method_copyArgumentType(Method m, unsigned int index)
// 選擇器相關
const char *sel_getName(SEL sel)
SEL sel_registerName(const char *str)
// 用 block 做爲方法實現
IMP imp_implementationWithBlock(id block)
id imp_getBlock(IMP anImp)
BOOL imp_removeBlock(IMP anImp)
複製代碼

關聯對象相關數據結構

傳送門:OC - Association 關聯對象app

// 添加關聯對象
void objc_setAssociatedObject(id object, const void * key, id value, objc_AssociationPolicy policy)
// 得到關聯對象
id objc_getAssociatedObject(id object, const void * key)
// 移除指定 object 的全部關聯對象
void objc_removeAssociatedObjects(id object)
複製代碼

Runtime 都有哪些應用?

  • 利用關聯對象(AssociatedObject)給分類添加屬性
  • 遍歷類的全部成員變量(修改 textfield 的佔位文字顏色、字典轉模型、自動歸檔解檔)
  • 交換方法實現(攔截交換系統的方法)
  • 利用消息轉發機制解決方法找不到的異常問題
  • ......

相關連接

蘋果維護的 Runtime 開源代碼
GNU 維護的 Runtime 開源代碼
蘋果官方文檔 Runtime框架

相關文章
相關標籤/搜索