iOS学习开发iOS漫步者程序猿阵线联盟-汇总各类技术干货

Runtime 交换方法

2018-04-03  本文已影响21人  留个念想给昨天

他喜欢创作,时常有充沛的表达诉求,
他喜欢听王菲的歌,也向往远方和自由。
他希望有人懂他偶尔的烦躁和头脑短路,
懂他有时写文案也是带着镣铐在跳舞。
然而,他洞察过那么多消费者的心,
却没有人还给他一个“懂得”。

于是他,转行了,做了iOS开发人!

写在前头

工作中,是不是经常这样用到NSURL
NSURL * url = [NSURL URLWithString:@"www.baidu.com"];
很简单,但是!!! 有个致命的隐藏问题 !!!!
当字符串中有中文,这个url就创建不成功,那么我们发送的请求就会出错。
是不是有这样的经历:发现一个问题,找bug找了半天,最后发现是url中有中文。。。(此处是不是想摔电脑)
那么有什么办法在不改变原有代码的情况下给URLWithString 添加一个检测是否为空的功能?

这里就要用到runtime的方法交互了。

image.png

1.创建NSURL的分类

#import <Foundation/Foundation.h>

@interface NSURL (url)

+(instancetype)My_URLWithString:(NSString *)URLString;

@end

#import "NSURL+url.h"
@implementation NSURL (url)

+(instancetype)My_URLWithString:(NSString *)URLString
{
    NSURL * url = [NSURL URLWithString:URLString];
    if (url == nil) {
        NSLog(@"哥么是一个空的URL");
    }
    return url;
    
}

@end

这个My_URLWithString 就是检测url为空的方法
那么应该怎么交换方法呢,什么时候交换呢

2.寻找方法交换的时机

每一个类,只要参与了编译,就会加载这个类,只要加载这个类就会调用这个类的load方法。
试一下

#import "NSURL+url.h"

@implementation NSURL (url)

+(void)load
{
    NSLog(@"%s",__func__);
    
}


+(instancetype) My_URLWithString:(NSString *)URLString
{
    NSURL * url = [NSURL URLWithString:URLString];
    if (url == nil) {
        NSLog(@"哥么这个URL为空");
    }
    return url;
    
}
@end

然后在ViewController中调用URLWithString:这个方法

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
 
    NSURL * url = [NSURL URLWithString:@"www.baidu.com/中文"];
}
@end

运行,会发现,没有引用NSURL+url 这个类,也没有调用My_URLWithString这个方法,这个load也走了。

image.png

那么,我们可以在load中添加方法交互

3.方法交换

#import "NSURL+url.h"
#import <objc/message.h>

@implementation NSURL (url)

+(void)load
{
    //获取类方法
    //1.类类型
    //2.方法编号
    Method URLWithStr = class_getClassMethod([NSURL class], @selector(URLWithString:));
    //My_URLWithString
    Method MyURLWithStr = class_getClassMethod([NSURL class], @selector(My_URLWithString:));
    //交换方法
    method_exchangeImplementations(URLWithStr, MyURLWithStr); 
    
}
+(instancetype)My_URLWithString:(NSString *)URLString
{
    NSURL * url = [NSURL URLWithString:URLString];
    if (url == nil) {
        NSLog(@"哥么这个URL为空");
    }
    return url;
}
@end

辛辛苦苦,来一发测试
打个断点,看有没有走My_URLWithString:方法

image.png

果断进来了,放开断点

image.png

百密一疏

+(instancetype)My_URLWithString:(NSString *)URLString
{
    //注意这里----一定一定要标注好
    NSURL * url = [NSURL My_URLWithString:URLString];
    if (url == nil) {
        NSLog(@"哥么这个URL为空");
    }
    return url;
    
}

这样就OK了。完美解决,没有改变原有的任何代码。
提供一份Demo,希望对你有帮助
想了解更多RunTime,可以参考:
Runtime 消息传递机制
Runtime 消息转发机制
写在最后:

希望这篇文章对您有帮助,最好就是实操一边,这样才能理解更深入。
当然如果您发现有可以优化的地方,希望您能慷慨的提出来。
最后祝您工作愉快!
上一篇下一篇

猜你喜欢

热点阅读