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]]; } //参数是空对象 else { [stringMethods appendString:@"nil"]; } //加个空格 if ([arrMethod indexOfObject:method] != arrMethod.count-2) { [stringMethods appendString:@" "]; } } } //打印出要调的类方法 NTLog(" Run Class Method: [%@ %@]", className, stringMethods); } #pragma mark TODO: + (void)LogInstance:(id)instance runMethod:(NSString *)methodName withArgs:(NSArray *)arguments { } @end