亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 系統 > iOS > 正文

iOS Runntime 動態添加類方法并調用-class_addMethod

2020-07-26 03:15:39
字體:
來源:轉載
供稿:網友

上手開發 iOS 一段時間后,我發現并不能只著眼于完成需求,利用閑暇之余多研究其他的開發技巧,才能在有限時間內提升自己水平。當然,“其他開發技巧”這個命題對于任何一個開發領域都感覺不找邊際,而對于我來說,嘗試接觸 objc/runtime 不失為是開始深入探索 iOS 開發的第一步。

剛了解 runtime 當然要從比較簡單的 api 開始,今天就羅列整理一下 class_addMethod 的相關點:

首先從文檔開始。

/** * Adds a new method to a class with a given name and implementation.* * @param cls The class to which to add a method.* @param name A selector that specifies the name of the method being added.* @param imp A function which is the implementation of the new method. The function must take at least two arguments―self and _cmd.* @param types An array of characters that describe the types of the arguments to the method. * * @return YES if the method was added successfully, otherwise NO * (for example, the class already contains a method implementation with that name).** @note class_addMethod will add an override of a superclass's implementation, * but will not replace an existing implementation in this class. * To change an existing implementation, use method_setImplementation.*/OBJC_EXPORT BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);

大意翻譯一下,這個方法的作用是,給類添加一個新的方法和該方法的具體實現。分析一下這個方法需要的參數:

Class cls

cls 參數表示需要添加新方法的類。

SEL name

name 參數表示 selector 的方法名稱,可以根據喜好自己進行命名。

IMP imp

imp 即 implementation ,表示由編譯器生成的、指向實現方法的指針。也就是說,這個指針指向的方法就是我們要添加的方法。

const char *types

最后一個參數 *types 表示我們要添加的方法的返回值和參數。

簡要介紹了 class_addMethod 中所需要的參數以及作用之后,我們就可以開始利用這個方法進行添加我們所需要的方法啦!在使用之前,我們首先要明確 Objective-C 作為一種動態語言,它會將部分代碼放置在運行時的過程中執行,而不是編譯時,所以在執行代碼時,不僅僅需要的是編譯器,也同時需要一個運行時環境(Runtime),為了滿足一些需求,蘋果開源了 Runtime Source 并提供了開放的 api 供開發者使用。

其次,我們需要知道在什么情況下需要調用 class_addMethod 這個方法。當項目中,需要繼承某一個類(subclass),但是父類中并沒有提供我需要的調用方法,而我又不清楚父類中某些方法的具體實現;或者,我需要為這個類寫一個分類(category),在這個分類中,我可能需要替換/新增某個方法(注意:不推薦在分類中重寫方法,而且也無法通過 super 來獲取所謂父類的方法)。大致在這兩種情況下,我們可以通過 class_addMethod 來實現我們想要的效果。

好了,說了這么多那么到底應該如何調用呢?如果不清楚使用方法,那么看說明書就是最好的方法。在 Apple 提供的文檔中就有詳細的使用方法(Objective-C Runtime Programming Guide - Dynamic Method Resolution),以下內容就以 myCar 這個類來詳細說明一下具體的使用規則:

首先,既然要給某個類添加我們的方法,就應該繼承或者給這個類寫一個分類,這里我新建一個名為「myCar」的類,作為「Car」類的分類。

#import "Car+myCar.h"@implementation Car (myCar)@end

我們知道,在 Objective-C 中,正常的調用方法是通過消息機制(message)來實現的,那么如果類中沒有找到發送的消息方法,系統就會進入找不到該方法的處理流程中,如果在這個流程中,我們加入我們所需要的新方法,就能實現運行過程中的動態添加了。這個流程或者說機制,就是 Objective-C 的 Message Forwarding

這個機制中所涉及的方法主要有兩個:

+ (BOOL)resolveInstanceMethod:(SEL)sel+ (BOOL)resolveClassMethod:(SEL)sel

兩個方法的唯一區別在于需要添加的是靜態方法還是實例方法。我們就拿前者來說,既然要添加方法,我們就在「myCar」類中實現它,代碼如下:

#import "Car+myCar.h"void startEngine(id self, SEL _cmd) {NSLog(@"my car starts the engine");}@implementation Car (myCar)@end

至此,我們實現了我們要添加的 startEngine 這個方法。這是一個 C 語言的函數,它至少包含了 self 和 _cmd 兩個參數(self 代表著函數本身,而 _cmd 則是一個 SEL 數據體,包含了具體的方法地址)。如果要在這個方法中新增參數呢?見如下代碼:

#import "Car+myCar.h"void startEngine(id self, SEL _cmd, NSString *brand) {NSLog(@"my %@ car starts the engine", brand);}@implementation Car (myCar)@end

只要在那兩個必須的參數之后添加所需要的參數和類型就可以了,返回值同樣道理,只要把方法名之前的 void 修改成我們想要的返回類型就可以,這里我們不需要返回值。

接著,我們重載 resolveInstanceMethod: 這個函數:

#import "Car+myCar.h"#import <objc/runtime.h>void startEngine(id self, SEL _cmd, NSString *brand) {NSLog(@"my %@ car starts the engine", brand);}@implementation Car (myCar)+ (BOOL)resolveInstanceMethod:(SEL)sel {if (sel == @selector(drive)) {class_addMethod([self class], sel, (IMP)startEngine, "v@:@");return YES;}return [super resolveInstanceMethod:sel];}@end

解釋一下,這個函數在 runtime 環境下,如果沒有找到該方法的實現的話就會執行。第一行判斷的是傳入的 SEL 名稱是否匹配,接著調用 class_addMethod 方法,傳入相應的參數。其中第三個參數傳入的是我們添加的 C 語言函數的實現,也就是說,第三個參數的名稱要和添加的具體函數名稱一致。第四個參數指的是函數的返回值以及參數內容。

至于該類方法的返回值,在我測試的時候,無論這個 BOOL 值是多少,并不會影響我們的執行目標,一般返回 YES 即可。

如果覺得用 C 語言風格寫新函數比較不適應,那么可以改寫成以下的代碼:

@implementation Car (myCar)+ (BOOL)resolveInstanceMethod:(SEL)sel {if (sel == @selector(drive)) {class_addMethod([self class], sel, class_getMethodImplementation(self, @selector(startEngine:)), "s@:@");return YES;}return [super resolveInstanceMethod:sel];}- (void)startEngine:(NSString *)brand {NSLog(@"my %@ car starts the engine", brand);}@end

其中 class_getMethodImplementation 意思就是獲取 SEL 的具體實現的指針。

然后創建一個新的類「DynamicSelector」,在這個新類中我們實現對「Car」的動態添加方法。

#import "DynamicSelector.h"#import "Car+myCar.h"@implementation DynamicSelector- (void)dynamicAddMethod {Car *c = [[Car alloc] init];[c performSelector:@selector(drive) withObject:@"bmw"];}@end

注意,在這里就不能使用 [self method:] 進行調用了,因為我們添加的方法是在運行時才執行,而編譯器只負責編譯時的方法檢索,一旦對一個對象沒有檢索到它的 drive 方法,就會報錯,所以這里我們使用 performSelector:withObject: 來進行調用,保存,運行。

2016-08-26 10:50:17.207 objc-runtime[76618:3031897] my bmw car starts the engineProgram ended with exit code: 0

打印結果符合我們期望實現的目標。如果需要返回值,方法類似。

以上所述是小編給大家介紹的iOS Runntime 動態添加類方法并調用-class_addMethod,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對武林網網站的支持!

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产精品久久97| 国产欧美一区二区三区久久人妖| 综合网中文字幕| 欧美日韩国产限制| 69视频在线播放| 精品国内自产拍在线观看| 亚洲japanese制服美女| 亚洲国产精品推荐| 中文字幕精品一区久久久久| 精品动漫一区二区| 亚洲精品久久久久久久久| 欧美大尺度在线观看| 国产欧美在线播放| 久久国产精品网站| 成人精品在线视频| 国产成人av在线播放| 中文字幕亚洲欧美日韩高清| 欧美丰满片xxx777| 人体精品一二三区| 神马久久桃色视频| 精品国产区一区二区三区在线观看| 日韩大片在线观看视频| 国产亚洲欧洲高清| 久久精品国产久精国产一老狼| 91精品综合久久久久久五月天| 久久精品久久久久电影| 2019中文字幕在线免费观看| 亚洲精品色婷婷福利天堂| 亚洲精品久久久久久久久| 久久久久久久国产精品视频| 亚洲第一网中文字幕| 深夜成人在线观看| 日韩av在线天堂网| 米奇精品一区二区三区在线观看| 欧美日韩国产精品一区二区三区四区| 国产综合在线观看视频| 亚洲人成77777在线观看网| 亚洲欧美日韩中文在线| 成人免费观看49www在线观看| 欧美性感美女h网站在线观看免费| 91免费看片在线| 在线看日韩av| 国产亚洲视频在线| 中文字幕在线观看亚洲| 2020国产精品视频| 26uuu另类亚洲欧美日本老年| 亚洲国产天堂久久综合| 国产精品久久婷婷六月丁香| 日韩精品高清在线| 欧美精品九九久久| 亚洲xxxxx性| 日本不卡免费高清视频| 在线观看免费高清视频97| 中文字幕精品在线| 欧美成人免费全部观看天天性色| 亚洲成人1234| 一区二区三区无码高清视频| 欧美国产日韩中文字幕在线| 91久久综合亚洲鲁鲁五月天| 亚洲欧美国产制服动漫| 青青久久aⅴ北条麻妃| 亚洲热线99精品视频| 欧洲精品毛片网站| 青草青草久热精品视频在线观看| 国产精品日韩av| 岛国精品视频在线播放| 亚洲一区二区在线播放| 日本午夜精品理论片a级appf发布| 亚洲成人精品在线| 国产精品亚洲自拍| 久久综合九色九九| 亚洲精品美女在线观看| 久久久999精品免费| 日韩精品亚洲精品| 一区二区欧美亚洲| 热久久视久久精品18亚洲精品| 国产欧美日韩精品专区| 欧美有码在线观看| 国产97在线亚洲| 91沈先生在线观看| 欧美xxxx综合视频| 亚洲国产99精品国自产| 久久av中文字幕| 成人免费网视频| 日韩在线观看av| 97婷婷涩涩精品一区| 在线观看精品自拍私拍| 97色在线视频| 日韩专区在线播放| 亚洲欧洲午夜一线一品| 国产精品女人网站| 黑人精品xxx一区一二区| 一区二区亚洲精品国产| 国产91在线播放精品91| 国产精品久久一| 中文字幕av日韩| 国产在线视频91| 欧美精品在线免费| 国产精品老女人视频| 亚洲国产精品久久久久秋霞不卡| 国产精品爽黄69| 中文字幕欧美精品日韩中文字幕| 国产精品久久9| 国产精品欧美一区二区| 亚洲自拍欧美色图| 日韩在线免费高清视频| 在线成人中文字幕| 这里只有精品在线播放| 青青精品视频播放| 日韩av影视在线| 欧美国产激情18| 日韩乱码在线视频| 欧美俄罗斯乱妇| 欧美激情高清视频| 国产日韩欧美在线视频观看| 狠狠躁夜夜躁人人爽天天天天97| 欧美久久精品一级黑人c片| 色偷偷888欧美精品久久久| 一区二区三区视频在线| 亚洲午夜av电影| 精品国产欧美一区二区五十路| 国产成人精品一区二区在线| 精品国产欧美一区二区三区成人| 国产伦精品一区二区三区精品视频| 欧美午夜性色大片在线观看| 欧美成人精品影院| 亚洲人成网在线播放| 51色欧美片视频在线观看| 亚洲黄色www网站| 国产成人91久久精品| 欧美在线观看一区二区三区| 欧美www在线| 欧美高清视频免费观看| 美女啪啪无遮挡免费久久网站| 91精品视频播放| 国产99久久精品一区二区永久免费| 亚洲视频免费一区| 精品国产一区二区三区久久狼5月| 国产精品入口日韩视频大尺度| 亚洲深夜福利视频| 国产欧美一区二区三区在线看| 久久国产精品久久久久久久久久| 欧美中文字幕视频在线观看| 国产精品久久电影观看| 欧美精品成人在线| 精品久久久久久久久久| 欧美中文字幕在线| 国内精品久久久| 456国产精品| 欧美野外wwwxxx| 欧美国产乱视频| 国产日韩在线观看av| 久久久久国产精品免费网站| 欧美另类高清videos| 精品久久香蕉国产线看观看亚洲| 91九色在线视频| 国产欧美一区二区三区久久| 91久久久久久久一区二区| 国产精品永久免费在线| 成人美女av在线直播| 国产日韩换脸av一区在线观看| 亚洲欧美一区二区激情| 成人黄色影片在线| 国产精品网红直播|