• 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("
    Run Class Method: [%@ %@]", className, stringMethods);
    }
    
    #pragma mark TODO:
    + (void)LogInstance:(id)instance runMethod:(NSString *)methodName withArgs:(NSArray *)arguments {
        
    }
    
    @end
  • 相关阅读:
    关于JDK 安装,以及Java环境的设置
    DHCP snooping
    解除破解正版Kindle电子书籍的版权限制
    广东地区电信官方DNS服务器
    Bash脚本15分钟进阶指导
    视听说英语
    华中师大2013新生群
    【强网杯2018】Gamebox
    【强网杯2018】逆向hide
    【Wechall.net挑战】Anderson Application Auditing
  • 原文地址:https://www.cnblogs.com/huangzizhu/p/4223601.html
Copyright © 2020-2023  润新知