你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> iOS Runntime 靜態添加類辦法並挪用-class_addMethod

iOS Runntime 靜態添加類辦法並挪用-class_addMethod

編輯:IOS開發綜合

上手開辟 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 engine
Program ended with exit code: 0

打印成果相符我們希冀完成的目的。假如須要前往值,辦法相似。

以上所述是小編給年夜家引見的IOS Runntime 靜態添加類辦法並挪用-class_addMethod,願望對年夜家有所贊助,假如年夜家有任何疑問請給我留言,小編會實時答復年夜家的。在此也異常感激年夜家對本站網站的支撐!

【iOS Runntime 靜態添加類辦法並挪用-class_addMethod】的相關資料介紹到這裡,希望對您有所幫助! 提示:不會對讀者因本文所帶來的任何損失負責。如果您支持就請把本站添加至收藏夾哦!

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved