標籤:
objc中可以通過動態啟動並執行方法調用第三方庫的函數
通過可以用下面的方法判斷工程是否引入了第三方的庫,如果引入,則可以通過NtSdkIMP擷取到對應方法的函數指標去執行代碼。如果沒有引入,則不執行。
通過擷取方法的imp指標,可以運行對應的函數,如果imp為空白,說明不包含所需要的庫和符號。
@interface ViewController ()@end@implementation ViewController- (int)printOneNumber:(int)number { NSLog(@"print number %d", number); return number + 1;}+ (NSString *)numberAddOne:(NSString *)num { NSInteger n = [num integerValue]; n++; NSString *ret = [NSString stringWithFormat:@"%ld", n]; NSLog(@"%@", ret); return ret;}
如上面 ViewController 包含有
printOneNumber
numberAddOne這兩個方法,
通常可以通過 int ret = [self printOneNumber:1] 調用來執行對應的函數方法也可以通過下面的imp來調用,過程比較複雜,但可以在沒有聲明或者引用對應標頭檔就可以執行對應代碼
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. NSString *methodName = @"printOneNumber:"; IMP imp = [NtSdkIMP getInstance:self method:methodName]; int (*func)(id, SEL, ...) = (void *)imp; if (func) { SEL selector = NSSelectorFromString(methodName); int ret = func(self, selector, 4); NSLog(@"%d", ret); } imp = [NtSdkIMP getClass:@"ViewController" method:@"numberAddOne:"]; id (*func2)(id, SEL, ...) = (void *)imp; if (func2) { SEL selector = NSSelectorFromString(@"numberAddOne:"); Class classA = NSClassFromString(@"ViewController"); id s = func2(classA, selector, @"4"); NSLog(@"%@",s); }}
如果返回的是nsobject對像,則需要用
id (*func2)(id, SEL, ...)
設定imp的格式
如果返回的是基礎資料類型(非執行個體對象),則需要
int (*func)(id, SEL, ...)
設定imp的格式
對應的NtSdkIMP代碼如下:
#import <Foundation/Foundation.h>@interface NtSdkIMP : NSObject/** * 擷取類方法的函數指標 * * @param className 對象 * @param methodName 方法 * * @return 函數指標 */+ (IMP)getClass:(NSString *)className method:(NSString *)methodName;/** * 擷取對象方法的函數指標 * * @param instance 對象 * @param methodName 方法 * * @return 函數指標 */+ (IMP)getInstance:(id)instance method:(NSString *)methodName;/** * 列印出要調用的類方法 * * @param className 類名 * @param methodName 方法名 * @param arguments 參數列表 */+ (void)LogClass:(NSString *)className runMethod:(NSString *)methodName withArgs:(NSArray *)arguments;/** * 列印出要調用的對象方法 * * @param className 類名 * @param methodName 方法名 * @param arguments 參數列表 */+ (void)LogInstance:(NSString *)instanceName runMethod:(NSString *)methodName withArgs:(NSArray *)arguments;@end
#import "NtSdkIMP.h"#import "NTLog.h"@implementation NtSdkIMP+ (IMP)getClass:(NSString *)className method:(NSString *)methodName { Class classA = NSClassFromString(className); //存在該類 if (classA) { NTLog(@"Class %@ Exist", className); SEL selector = NSSelectorFromString(methodName); //存在對應的方法 if ([classA respondsToSelector:selector]) { NTLog(@"Method %@ Exist", methodName); IMP imp = [classA methodForSelector:selector]; return imp; } //不存在對應的方法 else { NTLog(@"Method NOT %@ Exist", methodName); return NULL; } } //存在該類 else { NTLog(@"Class %@ NOT exist", className); return NULL; }}+ (IMP)getInstance:(id)instance method:(NSString *)methodName { //對象存在 if (instance) { NTLog(@"Instance %@ Exist", instance); } //對象不存在 else { NTLog(@"Instance %@ NOT Exist", instance); return NULL; } SEL selector = NSSelectorFromString(methodName); //存在對應方法 if ([instance respondsToSelector:selector]) { NTLog(@"Method %@ Exist", methodName); IMP imp = [instance methodForSelector:selector]; return imp; } //不存在對應方法 else { NTLog(@"Method %@ NOT Exist", methodName); return NULL; }}+ (void)LogClass:(NSString *)className runMethod:(NSString *)methodName withArgs:(NSArray *)arguments { NTLog(@"className:%@",className); NTLog(@"method:%@", methodName); for (NSObject *object in arguments) { NTLog(@"%@ %@", object.class, object); } //方法名隊列。如果沒有參數,不包括冒號,如果有多個參數,有冒號相隔,且最後一個方法名為@"" NSMutableArray *arrMethod = [NSMutableArray arrayWithArray:[methodName componentsSeparatedByString:@":"]]; //方法名不存在 if (arrMethod.count < 1) { NTLog(@"methodname is nil"); return; } NSMutableString *stringMethods = [[NSMutableString alloc] init]; NSUInteger i = 0; //不帶參數 if (arrMethod.count == 1) { [stringMethods appendString:[arrMethod firstObject]]; } //多個參數 else { for (NSString *method in arrMethod) { if ([method isEqualToString:@""]) { break;//最後一個是@"",需要去掉 } [stringMethods appendString:method]; [stringMethods appendString:@":"]; //參數不為空白對象 if ([arguments objectAtIndex:i]) { [stringMethods appendString:[[arguments objectAtIndex:i] description]]; } //參數是Null 物件 else { [stringMethods appendString:@"nil"]; } //加個空格 if ([arrMethod indexOfObject:method] != arrMethod.count-2) { [stringMethods appendString:@" "]; } } } //列印出要調的類方法 NTLog("\nRun Class Method: [%@ %@]", className, stringMethods);}#pragma mark TODO:+ (void)LogInstance:(id)instance runMethod:(NSString *)methodName withArgs:(NSArray *)arguments { }@end
ios 動態執行的代碼