ios 动态执行的代码

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("\nRun Class Method: [%@ %@]", className, stringMethods);
}

#pragma mark TODO:
+ (void)LogInstance:(id)instance runMethod:(NSString *)methodName withArgs:(NSArray *)arguments {
    
}

@end

 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。