美文网首页
二、运行时-交换方法

二、运行时-交换方法

作者: XDLee | 来源:发表于2016-04-18 12:25 被阅读398次

交换方法

1. 简单实现

1> 创建一个 Person 类,并定义两个方法 study 和 run,分别实现:

#import "Person.h"
@implementation Person
- (void)study {
    NSLog(@"study");
}

- (void)run {
    NSLog(@"run");
}
@end

2> 正常调用方法

int main(int argc, const char * argv[]) {
    @autoreleasepool {
    Person *p = [[Person alloc] init];    
    [p study];
    [p run];
}

执行程序,结果如下:


正常调用方法.png

3> 交换方法实现

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        Person *p = [[Person alloc] init];
        
        [p study];
        [p run];
        
        // 交换方法实现
        Method m1 = class_getInstanceMethod(objc_getClass("Person"), @selector(study));
        Method m2 = class_getInstanceMethod(objc_getClass("Person"), @selector(run));
        method_exchangeImplementations(m1, m2);
        
        [p study];
        [p run];
    }
    return 0;
}

执行程序,结果如下:

运行时交换方法实现.png

由运行结果可知:study 方法和 run 方法的实现的确被交换了。

2. 交换系统自带的方法

在实际开发中,交换方法最大的应用场景是`替换系统自带的方法。

2.1 举例分析

举个例子:从iOS6到iOS7,苹果的界面风格由 '拟物化' 转变为 '扁平化'。
'怎么快速适配?'
1> 设置图片是通过系统的 imageNamed 方法来实现的。
2> 如果要进行iOS7之后版本的适配,首先需要平面设计师做出一套扁平化的图片,然后对系统版本(systemVersion)进行判断: 大于7.0就是用扁平化图片。
3> 如果项目中很多地方都有设置图片的代码,就要在每一处都添加判断系统版本的代码,工作量十分庞大,很不现实。这个时候,就可以考虑使用运行时交换方法来解决问题。
'解决思路'
1> 假设旧图片的图片名为 'xxx.png',可以让平面设计师将新图片的图片名命名为'xxx_os7.png'
2> 自定义一个 'xx_imageNamed' 方法,在该方法中进行系统版本判断,如果大于7.0就使用'xxx_os7.png'的图片。
3> 交换自定义的 'xx_imageNamed' 方法 和 系统的 'imageNamed' 方法的实现

2.2 代码实现

1> 自定义 UIImage+Extension 分类

UIImage+Extension.h
#import <UIKit/UIKit.h>
@interface UIImage (Extension)
@end
UIImage+Extension.m
#import "UIImage+Extension.h"
#import <objc/runtime.h>

@implementation UIImage (Extension)
/**
 当某个类或者分类加载到内存的时候,会调用1次
 */
+ (void)load {
    
    Method m1 = class_getClassMethod(objc_getClass("UIImage"), @selector(imageNamed:));
    Method m2 = class_getClassMethod(objc_getClass("UIImage"), @selector(xd_imageNamed:));
    method_exchangeImplementations(m1, m2);
}

/**
  自定义方法
 */
+ (UIImage *)xd_imageNamed:(NSString *)name {
    // 获取当前设备的系统版本号 
    float version = [[UIDevice currentDevice].systemVersion floatValue];
    // 判断版本号,如果 >= 7.0,在图片名后面拼接 "_os7"
    if (version >= 7.0) {
        name = [name stringByAppendingString:@"_os7"];
    }
    // 这里需要特别注意: return的时候,使用的是自定义的方法,这个时候由于已经交换了方法,实际上调用的是系统的imageNamed方法'
    return [UIImage xd_imageNamed:name];
}

// 注意: 在分类中重写系统方法,不能满足要求
// 这种方式会导致系统原来的方法无法使用
//+ (UIImage *)imageNamed:(NSString *)name {
//    
//    float version = [[UIDevice currentDevice].systemVersion floatValue];
//    if (version >= 7.0) {
//        name = [name stringByAppendingString:@"_os7"];
//    }
//    // 会死循环
//    return [self imageNamed:name];
//}

@end

2> vc 中调用

#import "ViewController.h"

@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@end

@implementation ViewController

/**
 iOS6  -> iOS7
 拟物化 -> 扁平化
 */
- (void)viewDidLoad {
    [super viewDidLoad];
    // 正是因为交换了方法的实现,所以这里的代码不用做任何修改,就可以实现想要的效果
    self.imageView.image = [UIImage imageNamed:@"close"];
}
@end

相关文章

  • 二、运行时-交换方法

    交换方法 1. 简单实现 1> 创建一个 Person 类,并定义两个方法 study 和 run,分别实现: 2...

  • Runtime

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

  • Day3

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

  • iOS中Method Swizzling-坑点总结

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

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

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

  • iOS 之runtime消息传递和转发

    runtime 运行时,oc是一门动态性语言,程序在运行时可改变结构,如添加方法,交换方法等.其实runtime就...

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

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

  • iOS 方法交换 Method Swizzling

    什么是Method Swizzling Method Swizzling 就是方法交换,俗称黑魔法,主要是在运行时...

  • 运行时浅析

    1. 什么是运行时? / 例: 动态交换方法: 2....

  • 深入剖析Objective-C中的Swizzle

    有时候为了达到一些特殊的需求,我们会在运行时期交换两个方法的实现,用我们自己的方法替换原始方法。在OC运行时期,O...

网友评论

      本文标题:二、运行时-交换方法

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