Objective-C Runtime 執行時之六:拾遺
前面幾篇基本介紹了runtime中的大部分功能,包括對類與物件、成員變數與屬性、方法與訊息、分類與協議的處理。runtime大部分的功能都是圍繞這幾點來實現的。
本章的內容並不算重點,主要針對前文中對Objective-C Runtime Reference內容遺漏的地方做些補充。當然這並不能包含所有的內容。runtime還有許多內容,需要讀者去研究發現。
super
在Objective-C中,如果我們需要在類的方法中呼叫父類的方法時,通常都會用到super,如下所示:
1234567891011121314 | @interfaceMyViewController:UIViewController@end@implementation MyViewController-(void)viewDidLoad{[superviewDidLoad];// do something...}@end |
如何使用super我們都知道。現在的問題是,它是如何工作的呢?
首先我們需要知道的是super與self不同。self是類的一個隱藏引數,每個方法的實現的第一個引數即為self。而super並不是隱藏引數,它實際上只是一個”編譯器標示符”,它負責告訴編譯器,當呼叫viewDidLoad方法時,去呼叫父類的方法,而不是本類中的方法。而它實際上與self指向的是相同的訊息接收者。為了理解這一點,我們先來看看super的定義:
1 | structobjc_super{id receiver;ClasssuperClass;}; |
這個結構體有兩個成員:
- receiver:即訊息的實際接收者
- superClass:指標當前類的父類
當我們使用super來接收訊息時,編譯器會生成一個objc_super結構體。就上面的例子而言,這個結構體的receiver就是MyViewController物件,與self相同;superClass指向MyViewController的父類UIViewController。
接下來,傳送訊息時,不是呼叫objc_msgSend函式,而是呼叫objc_msgSendSuper函式,其宣告如下:
1 | id objc_msgSendSuper(structobjc_super *super,SEL op,...); |
該函式第一個引數即為前面生成的objc_super結構體,第二個引數是方法的selector。該函式實際的操作是:從objc_super結構體指向的superClass的方法列表開始查詢viewDidLoad的selector,找到後以objc->receiver去呼叫這個selector,而此時的操作流程就是如下方式了
1 | objc_msgSend(objc_super->receiver,@selector(viewDidLoad)) |
由於objc_super->receiver就是self本身,所以該方法實際與下面這個呼叫是相同的:
1 | objc_msgSend(self,@selector(viewDidLoad)) |
為了便於理解,我們看以下例項:
123456789101112 | @interfaceMyClass:NSObject@end@implementation MyClass-(void)test{NSLog(@"self class: %@",self.class);NSLog(@"super class: %@",super.class);}@end |
呼叫MyClass的test方法後,其輸出是:
12 | 2014-11-0815:55:03.256[824:209297]selfclass:MyClass2014-11-0815:55:03.256[824:209297]superclass:MyClass |
從上例中可以看到,兩者的輸出都是MyClass。大家可以自行用上面介紹的內容來梳理一下。
庫相關操作
庫相關的操作主要是用於獲取由系統提供的庫相關的資訊,主要包含以下函式:
12345678 | // 獲取所有載入的Objective-C框架和動態庫的名稱constchar**objc_copyImageNames(unsignedint*outCount);// 獲取指定類所在動態庫constchar*class_getImageName(Classcls);// 獲取指定庫或框架中所有類的類名constchar**objc_copyClassNamesForImage(constchar*image,unsignedint*outCount); |
通過這幾個函式,我們可以瞭解到某個類所有的庫,以及某個庫中包含哪些類。如下程式碼所示:
123456789 | NSLog(@"獲取指定類所在動態庫");NSLog(@"UIView's Framework: %s",class_getImageName(NSClassFromString(@"UIView")));NSLog(@"獲取指定庫或框架中所有類的類名");constchar**classes=objc_copyClassNamesForImage(class_getImageName(NSClassFromString(@"UIView")),&outCount);for(inti=0;i<outCount;i++){NSLog(@"class name: %s",classes[i]);} |
其輸出結果如下:
12345678910 | 2014-11-0812:57:32.689[747:184013]獲取指定類所在動態庫2014-11-0812:57:32.690[747:184013]UIView'sFramework:/System/Library/Frameworks/UIKit.framework/UIKit2014-11-0812:57:32.690[747:184013]獲取指定庫或框架中所有類的類名2014-11-0812:57:32.691[747:184013]classname:UIKeyboardPredictiveSettings2014-11-0812:57:32.691[747:184013]classname:_UIPickerViewTopFrame2014-11-0812:57:32.691[747:184013]classname:_UIOnePartImageView2014-11-0812:57:32.692[747:184013]classname:_UIPickerViewSelectionBar2014-11-0812:57:32.692[747:184013]classname:_UIPickerWheelView2014-11-0812:57:32.692[747:184013]classname:_UIPickerViewTestParameters...... |
塊操作
我們都知道block給我們帶到極大的方便,蘋果也不斷提供一些使用block的新的API。同時,蘋果在runtime中也提供了一些函式來支援針對block的操作,這些函式包括:
12345678 | // 建立一個指標函式的指標,該函式呼叫時會呼叫特定的blockIMP imp_implementationWithBlock(id block);// 返回與IMP(使用imp_implementationWithBlock建立的)相關的blockid imp_getBlock(IMP anImp);// 解除block與IMP(使用imp_implementationWithBlock建立的)的關聯關係,並釋放block的拷貝BOOLimp_removeBlock(IMP anImp); |
- imp_implementationWithBlock函式:引數block的簽名必須是method_return_type ^(id self, method_args …)形式的。該方法能讓我們使用block作為IMP。如下程式碼所示:
1234567891011121314151617 | @interfaceMyRuntimeBlock:NSObject@end@implementation MyRuntimeBlock@end// 測試程式碼IMP imp=imp_implementationWithBlock(^(id obj,NSString *str){NSLog(@"%@",str);});class_addMethod(MyRuntimeBlock.class,@selector(testBlock:),imp,"[email protected]:@");MyRuntimeBlock *runtime=[[MyRuntimeBlock alloc]init];[runtime performSelector:@selector(testBlock:)withObject:@"hello world!"]; |
輸出結果是
1 | 2014-11-0914:03:19.779[1172:395446]hello world! |
弱引用操作
12345 | // 載入弱引用指標引用的物件並返回id objc_loadWeak(id *location);// 儲存__weak變數的新值id objc_storeWeak(id *location,id obj); |
- objc_loadWeak函式:該函式載入一個弱指標引用的物件,並在對其做retain和autoreleasing操作後返回它。這樣,物件就可以在呼叫者使用它時保持足夠長的生命週期。該函式典型的用法是在任何有使用__weak變數的表示式中使用。
- objc_storeWeak函式:該函式的典型用法是用於__weak變數做為賦值物件時。
這兩個函式的具體實施在此不舉例,有興趣的小夥伴可以參考《Objective-C高階程式設計:iOS與OS X多執行緒和記憶體管理》中對__weak實現的介紹。
巨集定義
在runtime中,還定義了一些巨集定義供我們使用,有些值我們會經常用到,如表示BOOL值的YES/NO;而有些值不常用,如OBJC_ROOT_CLASS。在此我們做一個簡單的介紹。
布林值
12 | #define YES (BOOL)1#define NO (BOOL)0 |
這兩個巨集定義定義了表示布林值的常量,需要注意的是YES的值是1,而不是非0值。
空值
12 | #define nil __DARWIN_NULL#define Nil __DARWIN_NULL |
其中nil用於空的例項物件,而Nil用於空類物件。
分發函式原型
1 | #define OBJC_OLD_DISPATCH_PROTOTYPES 1 |
該巨集指明分發函式是否必須轉換為合適的函式指標型別。當值為0時,必須進行轉換
Objective-C根類
1 | #define OBJC_ROOT_CLASS |
如果我們定義了一個Objective-C根類,則編譯器會報錯,指明我們定義的類沒有指定一個基類。這種情況下,我們就可以使用這個巨集定義來避過這個編譯錯誤。該巨集在iOS 7.0後可用。
其實在NSObject的宣告中,我們就可以看到這個巨集的身影,如下所示:
123456 | __OSX_AVAILABLE_STARTING(__MAC_10_0,__IPHONE_2_0)OBJC_ROOT_CLASSOBJC_EXPORT@interfaceNSObject<NSObject>
相關推薦Objective-C Runtime 執行時之六:拾遺前面幾篇基本介紹了runtime中的大部分功能,包括對類與物件、成員變數與屬性、方法與訊息、分類與協議的處理。runtime大部分的功能都是圍繞這幾點來實現的。 本章的內容並不算重點,主要針對前文中對Objective-C Runtime Reference內容遺漏 Objective-C Runtime 執行時之五:協議與分類Objective-C中的分類允許我們通過給一個類新增方法來擴充它(但是通過category不能新增新的例項變數),並且我們不需要訪問類中的程式碼就可以做到。 Objective-C中的協議是普遍存在的介面定義方式,即在一個類中通過@protocol定義介面,在另外 Objective-C Runtime 執行時之二:成員變數與屬性在前面一篇文章中,我們介紹了Runtime中與類和物件相關的內容,從這章開始,我們將討論類實現細節相關的內容,主要包括類中成員變數,屬性,方法,協議與分類的實現。 本章的主要內容將聚集在Runtime對成員變數與屬性的處理。在討論之前,我們先介紹一個重要的概念:型別 Objective-C Runtime 執行時之三:方法與訊息前面我們討論了Runtime中對類和物件的處理,及對成員變數與屬性的處理。這一章,我們就要開始討論Runtime中最有意思的一部分:訊息處理機制。我們將詳細討論訊息的傳送及訊息的轉發。不過在討論訊息之前,我們先來了解一下與方法相關的一些內容。 基礎資料型別 SEL Objective-C Runtime 執行時之四:Method Swizzling理解Method Swizzling是學習runtime機制的一個很好的機會。在此不多做整理,僅翻譯由Mattt Thompson發表於nshipster的Method Swizzling一文。 Method Swizzling是改變一個selector的實際實現的 iOS學習筆記56(Runtime)-Objective-C Runtime 執行時之三:方法與訊息前面我們討論了Runtime中對類和物件的處理,及對成員變數與屬性的處理。這一章,我們就要開始討論Runtime中最有意思的一部分:訊息處理機制。我們將詳細討論訊息的傳送及訊息的轉發。不過在討論訊息之前,我們先來了解一下與方法相關的一些內容。 基礎資料型別 SEL Objective-C Runtime 執行時之一:類與物件Objective-C語言是一門動態語言,它將很多靜態語言在編譯和連結時期做的事放到了執行時來處理。這種動態語言的優勢在於:我們寫程式碼時更具靈活性,如我們可以把訊息轉發給我們想要的物件,或者隨意交換一個方法的實現等。 這種特性意味著Objective-C不僅需要一 Objective-C Runtime 執行時:成員變數(ivars)及屬性獲取類的成員變數和屬性: 在objc_class中,所有的成員變數、屬性的資訊是放在連結串列ivars中的。ivars是一個數組,陣列中每個元素是指向Ivar(變數資訊)的指標。runtime提供了豐富的函式來操作這一欄位。大體上可以分為以下幾類: 1.成員變數操作函式 [ObjectC]Runtime執行時之三:方法與訊息這一章,我們就要開始討論Runtime中最有意思的一部分:訊息處理機制。我們將詳細討論訊息的傳送及訊息的轉發。 基礎資料型別 SEL SEL又叫選擇器,是表示一個方法的selector的指標,其定義如下:typedef struct objc_selector *SEL;o iOS Runtime 執行時之三:訊息處理機制前面我們討論了Runtime中對類和物件的處理,及對成員變數與屬性的處理。這一章,我們就要開始討論Runtime中最有意思的一部分:訊息處理機制。我們將詳細討論訊息的傳送及訊息的轉發。不過在討論訊息之前,我們先來了解一下與方法相關的一些內容。 基礎資料型別 objective-c runtime安全措施之二:反注入《O'Reilly.Hacking.and.Securing.iOS.Applications>>讀書筆記 反注入:在類函式被呼叫前做完整性檢測(預防應用自定義函式或apple標準庫函式被修改或替換) 原理:呼叫dladdr()函式檢查類方法的基本資訊是否合法 [執行時]Objective-C的執行時程式設計(Runtime Programming)以前還真沒了解過Objective-C的執行時程式設計(Runtime Programming),今天特意在網上搜了下,原來這麼深奧啊 表示現在理解不了,先轉走了再說,之前轉載的文章都是大神們總結的綜合,轉載地址忘記註明了 ,抱歉。 -- [1] 版本和平臺 - C++11併發學習之六:執行緒池的實現為什麼要使用執行緒池? 目前的大多數網路伺服器,包括Web伺服器、Email伺服器以及資料庫伺服器等都具有一個共同點,就是單位時間內必須處理數目巨大的連線請求,但處理時間卻相對較短。 傳統多執行緒方案中我們採用的伺服器模型則是一旦接受到請求之後,即建立 C++ Primer高速入門之六:數組和指針borde ott 1.5 del word ans 12px 關聯 bre 更新:勘誤,delete [] 豬 我們知道,C語言以及早期的面向結構的語言差點兒都支持數組定義。比方整形數組int 女神[2]。表示有倆數: 女神[0], 女神[1]。她們都是 Objective-C runtime原始碼學習之IMP定址(不包括訊息轉發部分)寫在前面 前段時間寫了一篇部落格runtime如何通過selector找到對應的IMP地址?(分別考慮類方法和例項方法),這是在看《招聘一個靠譜的iOS》時回答第22題時總結的一篇部落格,不過這篇部落格中並沒有牽涉到底層的程式碼,而且也留下了幾個沒有解決的 多執行緒之六:併發設計模式什麼是設計模式 在軟體工程中,設計模式(design pattern)是對軟體設計中普遍存在(反覆出現)的各種問題 ,所提出的解決方案。 架構模式 – MVC – 分層 設計模式 – 提煉系統中的元件 程式碼模式(成例 Idiom) Objective-C runtime之執行時的基本特點(三)學了那麼久的Objective-C,給我的感覺就是它什麼都是動態的,你將會聽到一個新的名詞: 一、動態方法解析 1、+(BOOL) resolveInstanceMethod:(SEL) sel 這是NSObject根類提供的類方法,呼叫時機為當被呼叫的方法實現部分沒有找到,而訊息轉發機制啟動之前的這個 iOS開發之關於Runtime執行時:類與物件Objective-C語言是一門動態語言,它將很多靜態語言在編譯和連結時期做的事放到了執行時來處理。這種動態語言的優勢在於:我們寫程式碼時更具靈活性,如我們可以把訊息轉發給我們想要的物件,或者隨意交換一個方法的實現等。 這種特性意味著Objective-C不僅需要一個編譯器,還需要一個執行時系統 C++11併發學習之三:執行緒同步1.<mutex> 標頭檔案介紹 (1)Mutex系列類(四種) std::mutex,最基本的 Mutex 類。 std::recursive_mutex,遞迴 Mutex 類。 std::time_mutex,定時 Mutex 類。 std::recursive_ti C++11併發學習之四:執行緒同步(續)有時候,在第一個執行緒完成前,可能需要等待另一個執行緒執行完成。C++標準庫提供了一些工具可用於這種同步操作,形式上表現為條件變數(condition variable)和期望(future)。 一.條件變數(condition variable) C++標準庫對條件變數有兩套實現:std::c |