Runtime 交换方法
2018-04-03 本文已影响21人
留个念想给昨天
他喜欢创作,时常有充沛的表达诉求,
他喜欢听王菲的歌,也向往远方和自由。
他希望有人懂他偶尔的烦躁和头脑短路,
懂他有时写文案也是带着镣铐在跳舞。
然而,他洞察过那么多消费者的心,
却没有人还给他一个“懂得”。
于是他,转行了,做了iOS开发人!
写在前头
工作中,是不是经常这样用到NSURL
NSURL * url = [NSURL URLWithString:@"www.baidu.com"];
很简单,但是!!! 有个致命的隐藏问题 !!!!
当字符串中有中文,这个url就创建不成功,那么我们发送的请求就会出错。
是不是有这样的经历:发现一个问题,找bug找了半天,最后发现是url中有中文。。。(此处是不是想摔电脑)
那么有什么办法在不改变原有代码的情况下给URLWithString 添加一个检测是否为空的功能?
这里就要用到runtime的方法交互了。
image.png1.创建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百密一疏
+(instancetype)My_URLWithString:(NSString *)URLString
{
//注意这里----一定一定要标注好
NSURL * url = [NSURL My_URLWithString:URLString];
if (url == nil) {
NSLog(@"哥么这个URL为空");
}
return url;
}
这样就OK了。完美解决,没有改变原有的任何代码。
提供一份Demo,希望对你有帮助
想了解更多RunTime,可以参考:
Runtime 消息传递机制
Runtime 消息转发机制
写在最后:
希望这篇文章对您有帮助,最好就是实操一边,这样才能理解更深入。
当然如果您发现有可以优化的地方,希望您能慷慨的提出来。
最后祝您工作愉快!