美文网首页
运行时中的方法交换

运行时中的方法交换

作者: Chivalrous | 来源:发表于2016-08-12 19:50 被阅读60次

一个app在更新的时候如果需要更换一套新的图标,在不改动源代码的情况下,如何快速地完成这一任务呢?这种情况就可以使用方法交换来实现这个功能.

为了以后使用方便,我在这里写了一个分类,以后需要的时候就可以直接拿过来使用啦😄.

#import "UIImage+Skin.h"
#import <objc/runtime.h>

@implementation UIImage (Skin)

+ (void)load {
    // 获取原始的方法
    Method originMethod = class_getClassMethod([UIImage class], @selector(imageNamed:));
    
    // 获取新的方法
    Method newMethod = class_getClassMethod([UIImage class], @selector(customImageNamed:));
    
    // 交换方法
    method_exchangeImplementations(originMethod, newMethod);
    
}

+ (UIImage *)customImageNamed:(NSString *)name {

    NSString *skinFolderPath = [NSString stringWithFormat:@"%@/skins/%@",[NSBundle mainBundle].resourcePath,@"black"];
    
    NSString *path = nil;
    
    if([name hasSuffix:@".png"]) {
        path = [NSString stringWithFormat:@"%@/%@",skinFolderPath,name];
    } else {
        path = [NSString stringWithFormat:@"%@/%@.png",skinFolderPath,name];
    }
    
    UIImage *image = [UIImage imageWithContentsOfFile:path];
    if(image == nil) {
        image = [UIImage customImageNamed:name];
    }
    return image;
}

@end

随便找了两张图来看下效果,不要在意图片颜值😢.


avatar1.png
avatar2.png

在控制器中直接生成UIImage对象,并进行赋值.

- (void)viewDidLoad {
    [super viewDidLoad];
    self.imageView.image = [UIImage imageNamed:@"avatar2"];
}

当程序启动时所看到的图片并不是预先赋值时使用的图片avatar2,而是图片avatar1,也就是说我们使用运行时的方法交换达到了我们想要的结果.而在实际需求中我们只需要在分类中添加如上代码,并根据图片名称拼接出对应的字符串就可以在不更改源码的情况实现项目的需求.

Snip20160812_18.png

不过这里有一点需要注意,当程序启动时方法已经被加载到内存,使用Method进行方法交换时已经改变了该方法的IMP指针的指向,如下图:

Snip20160812_5.png

如果把分类中的代码稍作更改,比如这样:

#import <objc/runtime.h>

@implementation UIImage (Skin)

+ (void)load {
    // 获取原始的方法
    Method originMethod = class_getClassMethod([UIImage class], @selector(imageNamed:));
    
    // 获取新的方法
    Method newMethod = class_getClassMethod([UIImage class], @selector(customImageNamed:));
    
    // 交换方法
    method_exchangeImplementations(originMethod, newMethod);
    
}

+ (UIImage *)customImageNamed:(NSString *)name {
    
    // 注意点
    return [UIImage imageNamed:name];
    
}

@end

那么再运行程序就会直接崩溃,出现死循环.

Snip20160812_16.png
因为此时内存中方法的IMP指针已经发生了变化,如果继续使用系统自带的 imageNamed: 的方法,则实际上是在 customImageNamed: 内部又再一次调用了 customImageNamed: 方法,这就造成了方法的循环调用导致死循环.

另外附赠一篇对运行时讲解的比较到位的文章,虽然我看的不是很懂😄,下面是链接:Objc Runtime 深入学习

相关文章

  • 运行时中的方法交换

    一个app在更新的时候如果需要更换一套新的图标,在不改动源代码的情况下,如何快速地完成这一任务呢?这种情况就可以使...

  • iOS利用Runtime机制进行方法交换

    离职后得了空闲,今天跟大家分享一下运行时中的方法交换.其实iOS开发中,真正需求你用运行时写的代码并不多,但是作为...

  • Runtime

    runtime运行时机制1:通过runtime,实现方法交换(交换两个类方法、交换两个实例方法)2:通过runti...

  • Day3

    1 runtime运行时机制1:通过runtime,实现方法交换(交换两个类方法、交换两个实例方法)。2:通过ru...

  • ios-面试-runtime中黑魔法方法交换

    方法交换-原理 方法交换,传言中的runtime中的黑魔法! 依据runtime的机制,OC中类生成的对象在运行时...

  • iOS中Method Swizzling-坑点总结

    什么是Method Swizzling 实际上是方法交换。OC是个运行时语言,允许我们运行时修改方法,可以进行方法...

  • 对runtime做个总结

    在iOS动态运行时中,涉及到的有以下几个: 消息传递 方法缓存查找 消息转发 方法混淆(Method-Swizzl...

  • Ubuntu系统CPU、内存、网络、进程监控工具

    1.1 Top 作用:查看在系统中运行的进程或线程,以及CPU、内存、交换分区等运行方法:sudo top运行结果...

  • RunTime系统学习《二》

    运行时中所有方法解析: 1.设置获取对象的类 object_getClass(id _Nullable obj) ...

  • ios利用runTime进行方法交换-Method Swizzl

    利用oc运行时特性,进行方法交换,一般是把一些类方法交换成我们自己的方法,或者修改一些SDK的一些方法等.meth...

网友评论

      本文标题:运行时中的方法交换

      本文链接:https://www.haomeiwen.com/subject/fwgssttx.html