zoukankan      html  css  js  c++  java
  • iOS 运行时Runtime

    Runtime能做非常非常多的事情,但是不能为了使用runtime而使用,因为使用runtime会使代码的阅读性降低,使用也不方便。只能在不得已的情况下使用。

    以下介绍几个用法。

    导入#import <objc/message.h> 或者 #import <objc/runtime.h>

    一、发消息objc_msgSend();

    a、获取一个类 objc_getClass();  

    b、注册一个方法 sel_registerName();

    c、获取一个方法 sel_getUid();

    //创建一个对象
        
        //NSObject * obj = [NSObject alloc];
        //id obj = objc_msgSend([NSObject class], @selector(alloc));
        //发生消息,调用alloc方法,和上面两句代码都是等价的,他的作用都是一样
        id obj = objc_msgSend(objc_getClass("NSObject"), sel_registerName("alloc"));
        
        //obj = [obj init];
        //obj = objc_msgSend(obj, @selector(init));
        //发生消息,调用init方法,和上面两句代码都是等价的,他的作用都是一样
        obj =  objc_msgSend(obj, sel_registerName("init"));/*
         objc_getClass("类名") 获取一个类
         sel_registerName("方法名") 注册一个方法
         */

    二、方法交换

    这里拿UIImage为例,添加一个UIImage的分类UIImage+jh.m

    重新类方法+load

    +(void)load{
        //根据类获取类方法imageNamed
        Method imageNamedMethod = class_getClassMethod(self, @selector(imageNamed:));
        //根据类获取类方法xg_imageNamed
        Method xg_imageNamedMethod = class_getClassMethod(self, @selector(xg_imageNamed:));
        //交换方法
        method_exchangeImplementations(imageNamedMethod, xg_imageNamedMethod);
    }

    写一个交换的方法xg_imageName:

    +(UIImage *)xg_imageNamed:(NSString *)name{
        //这里调用xg_imageNamed: 不是调用当前这个方法,因为我们在load中已经交换了imageNamed:这个方法,所以,这里调用xg_imageNamed:就会调用imageNamed:方法。
        UIImage * image = [UIImage xg_imageNamed:name];
        if (image) {
            NSLog(@"%@图片加载成功!",name);
        }else{
            NSLog(@"%@图片加载失败!",name);
        }
        return image;
    };

    所以我们在使用系统方法imageNamed:的时候就会调用xg_imageNamed:这个方法。

    UIImage * image = [UIImage imageNamed:@"1.png"];

    这样能够判断一个图片是否加载成功,而不需要修改系统方法,也不需要修改其他代码,方便扩展和开发。

    三、动态添加属性

    比如我需要给系统的NSObject类添加一个属性,那么大家都会想到使用分类添加一个属性,然后手动写setting和getting方法。

    使用runtime也是一样,不过在写setting和getting方法的时候不太一样,使用runtime会方便非常多。比如加一个name的方法

    添加一个NSObject+pro分类

    NSObject+pro.h

    #import <Foundation/Foundation.h>
    
    @interface NSObject (pro)
    
    /**
     添加一个name属性
     */
    @property NSString * name;
    
    @end

    NSObject+pro.m

    #import "NSObject+pro.h"
    #import <objc/message.h>
    
    @implementation NSObject (pro)
    
    //写setting方法
    -(void)setName:(NSString *)name{
        //设置一个关联 ,因为我们所有的属性其实就是一个关联
        //objc_setAssociatedObject(给哪个对象添加关联, @"关联名称", 关联的值, 修饰(我这里name是一个字符串,所有使用了copy));
        objc_setAssociatedObject(self, @"name", name, OBJC_ASSOCIATION_COPY_NONATOMIC);
    }
    
    //写getting方法
    -(NSString *)name{
        return objc_getAssociatedObject(self, @"name");
    }
    
    @end

    使用的时候就可以直接.name了

    NSObject * object = [[NSObject alloc]init];
        object.name = @"123";
        NSLog(@"name:%@",object.name);

    四、动态添加方法

    创建一个Person : NSObject 类

    在viewDidLoad方法执行以下代码

    Person * p = [[Person alloc]init];
        //这里调用eat:方法,但是在person中并没有这个方法,而在运行的使用动态创建
        [p performSelector:@selector(eat:) withObject:@"apple"];
        //这里调用run方法并且返回一个结果,但是在person中并没有这个方法,而在运行的使用动态创建
        NSNumber * i = [p performSelector:@selector(run)];
        NSLog(@"p run :%@",i);

    那么来看看是怎么动态添加

    person.h文件是空的,什么都没有。

    #import <Foundation/Foundation.h>
    
    @interface Person : NSObject
    
    @end

    主要看person.m文件

    #import "Person.h"
    #import <objc/message.h>
    
    @implementation Person
    
    //eat:方法的实现
    void tEat(id self , SEL _cmd ,NSString * e){
        NSLog(@"Person eat :%@",e);
    }
    
    //run方法的实现
    NSNumber * tRun(id self , SEL _cmd){
        return @100;
    }
    
    //但运行的时候,找不到某个方法就会执行
    +(BOOL)resolveInstanceMethod:(SEL)sel{
        //判断是不是找不到eat:方法
        if (sel == NSSelectorFromString(@"eat:")) {
            /*
             添加方法
             */
            //class :给谁(那个类)添加方法
            //SEL :添加什么方法
            //imp :方法的实现 -》函数 - 》 函数入口 - 》 函数名
            //type :方法类型 方法类型怎么描述查看开发文档 Objective-C Runtime Programming Guide > Type Encodings.可以按住option键点击下面class_addMethod()函数,在方法说明里面用“不是黑色的字体”描述,可以直接跳转到对应说明
            class_addMethod(self, sel, (IMP)tEat, "v@:@");
            return YES;
        }
        //判断是不是找不到run 方法
        if (sel == NSSelectorFromString(@"run")) {
            class_addMethod(self, sel, (IMP)tRun, "@@:");
            return YES;
        }
        
        return [super resolveInstanceMethod:sel];
    }
    
    @end

    五、获取成员变量和类型

    添加一个分类 NSObject+runtime

    NSObject+runtime.h文件

    #import <Foundation/Foundation.h>
    
    @interface NSObject (runtime)
    
    //获取所有的成员变量
    +(instancetype)getAllIvar;
    
    @end

    NSObject+runtime.m文件

    #import "NSObject+runtime.h"
    #import <objc/message.h>
    
    @implementation NSObject (runtime)
    
    +(instancetype)getAllIvar{
        id obj = [[self alloc]init];
        unsigned int outCount = 0;
        //获取成员变量列表
        Ivar * varList =  class_copyIvarList(self, &outCount);
        for (int i = 0; i< outCount; i++) {
            Ivar ivar = varList[i];
            //获取成员变量名
            NSString * ivarName = [NSString stringWithUTF8String:ivar_getName(ivar)];
            ivarName = [ivarName substringFromIndex:1];
            NSLog(@"成员变量名称:%@",ivarName);
            
            //给属性赋值,value不可以为nil
            id value;
            //现在假设value 不为nil
            [obj setValue:value forKey:ivarName];
            
            //获取成员变量类型
            NSString *ivarType = [NSString stringWithUTF8String:ivar_getTypeEncoding(ivar)];
            ivarType = [ivarType stringByReplacingOccurrencesOfString:@""" withString:@""];
            ivarType = [ivarType stringByReplacingOccurrencesOfString:@"@" withString:@""];
            //跟成员变量类型 得到对应的类
            Class class = NSClassFromString(ivarType);
            NSLog(@"成员变量的类型是:%@",class);
        }
        return obj;
    }
    @end
  • 相关阅读:
    iphone备忘录存储路径
    wp7常用Task,启动器与选择器
    sql ce 修改表数据
    MessageBox.Show()中的换行
    莫名异常
    wp7中设置toolkit的工具栏图标不能正常显示(DatePicker和TimePicker)
    json 解析
    wp7弹出提示框退出程序
    第一个ios程序
    TextBox只显示数字
  • 原文地址:https://www.cnblogs.com/qq9070/p/6796003.html
Copyright © 2011-2022 走看看