Objective-C Runtime 運行時之六:拾遺

原文出處:南峰子的技術(shù)博客

前面幾篇基本介紹了runtime中的大部分功能臀蛛,包括對類與對象繁成、成員變量與屬性焚辅、方法與消息、分類與協(xié)議的處理誓军。runtime大部分的功能都是圍繞這幾點來實現(xiàn)的袱讹。

本章的內(nèi)容并不算重點,主要針對前文中對Objective-C Runtime Reference內(nèi)容遺漏的地方做些補充昵时。當然這并不能包含所有的內(nèi)容捷雕。runtime還有許多內(nèi)容,需要讀者去研究發(fā)現(xiàn)债查。

super

在Objective-C中非区,如果我們需要在類的方法中調(diào)用父類的方法時,通常都會用到super盹廷,如下所示:

@implementation MyViewController

-(void)viewDidLoad {

[super viewDidLoad];

// do something

}

@end

如何使用super我們都知道≌鞒瘢現(xiàn)在的問題是,它是如何工作的呢?

首先我們需要知道的是super與self不同管怠。self是類的一個隱藏參數(shù)淆衷,每個方法的實現(xiàn)的第一個參數(shù)即為self。而super并不是隱藏參數(shù)渤弛,它實際上只是一個”編譯器標示符”祝拯,它負責告訴編譯器,當調(diào)用viewDidLoad方法時她肯,去調(diào)用父類的方法佳头,而不是本類中的方法。而它實際上與self指向的是相同的消息接收者晴氨。為了理解這一點康嘉,我們先來看看super的定義:

struct objc_super { id receiver; Class superClass; };

這個結(jié)構(gòu)體有兩個成員:

1)receiver:即消息的實際接收者

2)superClass:指針當前類的父類

當我們使用super來接收消息時,編譯器會生成一個objc_super結(jié)構(gòu)體籽前。就上面的例子而言亭珍,這個結(jié)構(gòu)體的receiver就是MyViewController對象,與self相同枝哄;superClass指向MyViewController的父類UIViewController肄梨。

接下來,發(fā)送消息時挠锥,不是調(diào)用objc_msgSend函數(shù)众羡,而是調(diào)用objc_msgSendSuper函數(shù),其聲明如下:

id objc_msgSendSuper ( struct objc_super *super, SEL op, ... );

該函數(shù)第一個參數(shù)即為前面生成的objc_super結(jié)構(gòu)體瘪贱,第二個參數(shù)是方法的selector纱控。該函數(shù)實際的操作是:從objc_super結(jié)構(gòu)體指向的superClass的方法列表開始查找viewDidLoad的selector,找到后以objc->receiver去調(diào)用這個selector菜秦,而此時的操作流程就是如下方式了

objc_msgSend(objc_super->receiver, @selector(viewDidLoad))

由于objc_super->receiver就是self本身甜害,所以該方法實際與下面這個調(diào)用是相同的:

objc_msgSend(self, @selector(viewDidLoad))

為了便于理解,我們看以下實例:

@implementation MyClass

-(void)test {

NSLog(@"self class: %@",self.class);

NSLog(@"super class: %@",super.class);

}

@end

調(diào)用MyClass的test方法后球昨,其輸出是:

2014-11-0815:55:03.256[824:209297]selfclass:MyClass

2014-11-0815:55:03.256[824:209297]superclass:MyClass

從上例中可以看到尔店,兩者的輸出都是MyClass。大家可以自行用上面介紹的內(nèi)容來梳理一下主慰。

庫相關(guān)操作

庫相關(guān)的操作主要是用于獲取由系統(tǒng)提供的庫相關(guān)的信息嚣州,主要包含以下函數(shù):

// 獲取所有加載的Objective-C框架和動態(tài)庫的名稱

const char ** objc_copyImageNames ( unsigned int *outCount );

// 獲取指定類所在動態(tài)庫

const char * class_getImageName ( Class cls );

// 獲取指定庫或框架中所有類的類名

const char ** objc_copyClassNamesForImage ( const char *image, unsigned int *outCount );

通過這幾個函數(shù),我們可以了解到某個類所有的庫共螺,以及某個庫中包含哪些類该肴。如下代碼所示:

示例代碼

想看打印結(jié)果,就自己動手吧藐不!

塊操作

我們都知道block給我們帶到極大的方便匀哄,蘋果也不斷提供一些使用block的新的API秦效。同時,蘋果在runtime中也提供了一些函數(shù)來支持針對block的操作涎嚼,這些函數(shù)包括:

// 創(chuàng)建一個指針函數(shù)的指針阱州,該函數(shù)調(diào)用時會調(diào)用特定的block

IMP imp_implementationWithBlock(id block);

// 返回與IMP(使用imp_implementationWithBlock創(chuàng)建的)相關(guān)的block

id imp_getBlock(IMP anImp);

// 解除block與IMP(使用imp_implementationWithBlock創(chuàng)建的)的關(guān)聯(lián)關(guān)系,并釋放block的拷貝

BOO Limp_removeBlock(IMP anImp);

imp_implementationWithBlock函數(shù):參數(shù)block的簽名必須是method_return_type ^(id self, method_args …)形式的法梯。該方法能讓我們使用block作為IMP苔货。如下代碼所示:

@interface MyRuntimeBlock : NSObject

@end

@implementation MyRuntimeBlock

@end

// 測試代碼

IMP imp = imp_implementationWithBlock(^(id obj, NSString *str) {

? NSLog(@"%@", str);

});

class_addMethod(MyRuntimeBlock.class, @selector(testBlock:), imp, "v@:@");

MyRuntimeBlock *runtime = [[MyRuntimeBlock alloc] init];

[runtime performSelector:@selector(testBlock:) withObject:@"hello world!"];

輸出結(jié)果是

2014-11-09 14:03:19.779 [1172:395446] hello world!

弱引用操作

// 加載弱引用指針引用的對象并返回

id objc_loadWeak ( id *location );

// 存儲__weak變量的新值

id objc_storeWeak ( id *location, id obj );

1)objc_loadWeak函數(shù):該函數(shù)加載一個弱指針引用的對象,并在對其做retain和autoreleasing操作后返回它立哑。這樣夜惭,對象就可以在調(diào)用者使用它時保持足夠長的生命周期。該函數(shù)典型的用法是在任何有使用__weak變量的表達式中使用刁憋。

2)objc_storeWeak函數(shù):該函數(shù)的典型用法是用于__weak變量做為賦值對象時滥嘴。

這兩個函數(shù)的具體實施在此不舉例,有興趣的小伙伴可以參考《Objective-C高級編程:iOS與OS X多線程和內(nèi)存管理》中對__weak實現(xiàn)的介紹至耻。

宏定義

在runtime中,還定義了一些宏定義供我們使用镊叁,有些值我們會經(jīng)常用到尘颓,如表示BOOL值的YES/NO;而有些值不常用晦譬,如OBJC_ROOT_CLASS疤苹。在此我們做一個簡單的介紹。

布爾值

#define YES? (BOOL)1

#define NO?? (BOOL)0

這兩個宏定義定義了表示布爾值的常量敛腌,需要注意的是YES的值是1卧土,而不是非0值。

空值

#define nil? __DARWIN_NULL

#define Nil??__DARWIN_NULL

其中nil用于空的實例對象像樊,而Nil用于空類對象尤莺。

分發(fā)函數(shù)原型

#define OBJC_OLD_DISPATCH_PROTOTYPES? 1

該宏指明分發(fā)函數(shù)是否必須轉(zhuǎn)換為合適的函數(shù)指針類型。當值為0時生棍,必須進行轉(zhuǎn)換

Objective-C根類

#define OBJC_ROOT_CLASS

如果我們定義了一個Objective-C根類颤霎,則編譯器會報錯,指明我們定義的類沒有指定一個基類涂滴。這種情況下友酱,我們就可以使用這個宏定義來避過這個編譯錯誤。該宏在iOS 7.0后可用柔纵。

其實在NSObject的聲明中缔杉,我們就可以看到這個宏的身影,如下所示:

__OSX_AVAILABLE_STARTING(__MAC_10_0,__IPHONE_2_0)

OBJC_ROOT_CLASS

OBJC_EXPORT

@interface NSObject {

? Class isa OBJC_ISA_AVAILABILITY;

}

我們可以參考這種方式來定義我們自己的根類搁料。

局部變量存儲時長

#define NS_VALID_UNTIL_END_OF_SCOPE

該宏表明存儲在某些局部變量中的值在優(yōu)化時不應(yīng)該被編譯器強制釋放或详。

我們將局部變量標記為id類型或者是指向ObjC對象類型的指針系羞,以便存儲在這些局部變量中的值在優(yōu)化時不會被編譯器強制釋放。相反鸭叙,這些值會在變量再次被賦值之前或者局部變量的作用域結(jié)束之前都會被保存觉啊。

關(guān)聯(lián)對象行為

enum{

OBJC_ASSOCIATION_ASSIGN=0,

OBJC_ASSOCIATION_RETAIN_NONATOMIC=1,

OBJC_ASSOCIATION_COPY_NONATOMIC=3,

OBJC_ASSOCIATION_RETAIN=01401,

OBJC_ASSOCIATION_COPY=01403

};

這幾個值在前面已介紹過,在此不再重復(fù)沈贝。

總結(jié)

至此杠人,本系列對runtime的整理已完結(jié)。當然這只是對runtime的一些基礎(chǔ)知識的歸納宋下,力圖起個拋磚引玉的作用嗡善。還有許多關(guān)于runtime有意思東西還需要讀者自己去探索發(fā)現(xiàn)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末学歧,一起剝皮案震驚了整個濱河市罩引,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌枝笨,老刑警劉巖袁铐,帶你破解...
    沈念sama閱讀 217,907評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異横浑,居然都是意外死亡剔桨,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評論 3 395
  • 文/潘曉璐 我一進店門徙融,熙熙樓的掌柜王于貴愁眉苦臉地迎上來洒缀,“玉大人,你說我怎么就攤上這事欺冀∈骷ǎ” “怎么了?”我有些...
    開封第一講書人閱讀 164,298評論 0 354
  • 文/不壞的土叔 我叫張陵隐轩,是天一觀的道長饺饭。 經(jīng)常有香客問我,道長龙助,這世上最難降的妖魔是什么砰奕? 我笑而不...
    開封第一講書人閱讀 58,586評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮提鸟,結(jié)果婚禮上军援,老公的妹妹穿的比我還像新娘。我一直安慰自己称勋,他們只是感情好胸哥,可當我...
    茶點故事閱讀 67,633評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著赡鲜,像睡著了一般空厌。 火紅的嫁衣襯著肌膚如雪庐船。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,488評論 1 302
  • 那天嘲更,我揣著相機與錄音筐钟,去河邊找鬼。 笑死赋朦,一個胖子當著我的面吹牛篓冲,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播宠哄,決...
    沈念sama閱讀 40,275評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼壹将,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了毛嫉?” 一聲冷哼從身側(cè)響起诽俯,我...
    開封第一講書人閱讀 39,176評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎承粤,沒想到半個月后暴区,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,619評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡辛臊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,819評論 3 336
  • 正文 我和宋清朗相戀三年颜启,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片浪讳。...
    茶點故事閱讀 39,932評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖涌萤,靈堂內(nèi)的尸體忽然破棺而出淹遵,到底是詐尸還是另有隱情,我是刑警寧澤负溪,帶...
    沈念sama閱讀 35,655評論 5 346
  • 正文 年R本政府宣布透揣,位于F島的核電站,受9級特大地震影響川抡,放射性物質(zhì)發(fā)生泄漏辐真。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,265評論 3 329
  • 文/蒙蒙 一崖堤、第九天 我趴在偏房一處隱蔽的房頂上張望侍咱。 院中可真熱鬧,春花似錦密幔、人聲如沸楔脯。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽昧廷。三九已至堪嫂,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間木柬,已是汗流浹背皆串。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留眉枕,地道東北人恶复。 一個月前我還...
    沈念sama閱讀 48,095評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像齐遵,于是被迫代替她去往敵國和親寂玲。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,884評論 2 354

推薦閱讀更多精彩內(nèi)容