• Runtime 应用(一)拦截系统自带的方法交换实现


    动态的交换方法能够给项目中大量已经使用的方法 进行拦截增加操作

    实践:利用运行时交换系统的ImageNamed:方法

    应用背景

    当系统需要适配ios7和ios8时可能会有显示不同图片的需求,但在老项目上开发ios7程序时并未考虑到ios8的适配,当项目上有几百处地方用到ImageNamed:方法时,如果选用最直接的办法,在该方法之前进行判断,如果为ios8就显示另外一张图片,这样的工作量明显会很大,所以可以用运行时的方法来解决。

    新建一个项目,准备两张图片,一张图片名为close为ios7而准备,一张close_os8为ios8而准备

    在storyboard里添加两个个UIImageView控件

    @interface ViewController ()
    @property (weak, nonatomic) IBOutlet UIImageView *img1;
    @property (weak, nonatomic) IBOutlet UIImageView *img2;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        self.img1.image = [UIImage imageNamed:@"close"];
        self.img2.image = [UIImage imageNamed:@"fire"];
        
    }
    
    @end

    接下来使用运行时的方法交换imageNamed:的实现,先为UiImage添加一个自定义的创建图片的分类,此时需要导入一个运行时框架 #import<objc/runtime.h>,

    代码如下:

    /**
     *  自定义创建图片方法
     */
    + (instancetype)imageWithName:(NSString *)name
    {
        NSString *imgN = name;
        double version = [[UIDevice currentDevice].systemVersion doubleValue];
        NSLog(@"%f",version);
        if (version >= 8.0) {
            imgN = [NSString stringWithFormat:@"%@_os8",name];
            NSLog(@"%@",imgN);
        }
        // 此时imageWithName:的实现在运行时已经被改为imageNamed:的实现
        return [self imageWithName:imgN];
    }

    在load方法里面实现方法的交换,该方法只会被加载一次

    /**
     *  类第一次加载进内存的时候会调用
     */
    + (void)load
    {
        // 运行时交换两个方法的实现
        Method m1 = class_getClassMethod([UIImage class], @selector(imageNamed:));
        Method m2 = class_getClassMethod([UIImage class], @selector(imageWithName:));
        method_exchangeImplementations(m1, m2);
        
    }

     如此就利用运行时机制实现了系统方法和自定义方法互相交换实现

    需要了解的知识点

    一、什么是运行时

         运行时是一套纯C语言的API,编译器最终都会将OC代码转化为运行时代码。

    二、运行时常用函数

    1、<objc/runtime.h>

    * 获得某个类的类方法 Method class_getClassMethod(Class cls, SEL name)

    * 获得某个对象的对象方法 Method class_getInstanceMethod(Class cls, SEL name)

    * 交换两个方法的实现 void method_exchangeImplementations(Method m1, Method m2)

    * 关联对象(将值value与对象object关联起来) void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)

    参数key:将来可以通过key取出这个存储的值

    参数policy:存储策略(assign、copy、retain)

    * 利用参数key将对象中存储的对应值取出 id objc_getAssociatedObject(id object, const void *key)

    * 获得某个类的所有成员变量 Ivar *class_copyIvarList(Class cls, unsigned int *outCount)(outCount会返回成员变量的总数)

    * 获得成员变量的名字 const char *ivar_getName(Ivar v)

    * 获得成员变量的类型 const char *ivar_getTypeEncoding(Ivar v)

    * 释放内存 void      free(void *) (当C语言函数名中包含了copy、create、retain、new等词语,那么就需要在最后释放资源)

    2、<objc/message.h>

    * 给某个对象发送某个消息 void objc_msgSend(void)

  • 相关阅读:
    C#水晶报表的分页统计字段
    ymPrompt消息提示组件js实现
    C#委托学习 原文推荐:http://www.cnblogs.com/warensoft/archive/2010/03/19/1689806.html?login=1#commentform
    C#之winfrom打印图片
    TreeView控件如何设置节点显示与隐藏,主要是用来做后台权限,没有权限的就隐藏,有权限的就显示?
    C#多线程间同步实例 原文:http://blog.csdn.net/zhoufoxcn/article/details/2453803
    C#反射的应用 原文摘自:http://blog.csdn.net/Tsapi/article/details/6234205
    C#编写的winform程序打包方法
    虚拟机下的CentOS环境中安装Node.js和npm
    RequireJS模块化与GruntJS构建
  • 原文地址:https://www.cnblogs.com/junhuawang/p/5798757.html
Copyright © 2020-2023  润新知