我们在使用NSURLRequest时,传入请求地址URL,但是如果URL中有中文的话,我们会发现NSURLRequest的请求地址会报空
- (void)viewDidLoad {
[super viewDidLoad];
NSURL * url =[NSURL URLWithString:@"http://www.baidu.com/中文"];
NSURLRequest * request =[NSURLRequest requestWithURL:url];
NSLog(@"%@",request);
}
//2018-04-23 10:08:23.719236+0800 003-HOOK[947:5550247] { URL: (null) }
那我们有没有办法改进呢?做下尝试
我们创建一个继承自NSURL的类,命名为HOOK,然后新建一个方法
#import
@interface NSURL (HOOK)
+(instancetype)HK_URLWithString:(NSString *)URLString;
@end
#import "NSURL+HOOK.h"
@implementation NSURL (HOOK)
+(instancetype)HK_URLWithString:(NSString *)URLString{
NSURL * url = [NSURL URLWithString:URLString];
if(url ==nil){
NSLog(@"空了");
}
return url;
}
@end
此时我们需要在ViewController.h导入NSURL+HOOK.h文件,还需要修改调用的方法名HK_URLWithString
#import "ViewController.h"
#import "NSURL+HOOK.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSURL * url =[NSURL HK_URLWithString:@"http://www.baidu.com/中文"];
NSURLRequest * request =[NSURLRequest requestWithURL:url];
NSLog(@"%@",request);
}
//2018-04-23 10:30:38.145984+0800 003-HOOK[1168:5566807] 空了
//2018-04-23 10:30:38.146393+0800 003-HOOK[1168:5566807] { URL: (null) }
那有没有更简洁的方式呢?可以利用Runtime运行时改变方法调用的顺序,在NSURL+HOOK.m文件修改
//
// NSURL+HOOK.m
// 003-HOOK
//
// Created by mac on 2018/4/23.
// Copyright © 2018年 mac. All rights reserved.
// 哪里HOOK?
/**
利用Runtime运行时改变方法调用的顺序
*/
#import "NSURL+HOOK.h"
#import
@implementation NSURL (HOOK)
+(void)load{
//获取两个Method
Method URLWithStr = class_getClassMethod(self, @selector(URLWithString:));
Method HKWithStr = class_getClassMethod(self, @selector(HK_URLWithString:));
//交换方法的IMP
method_exchangeImplementations(URLWithStr, HKWithStr);
}
//重写URLWithString
//+(instancetype)URLWithString:(NSString *)URLString{
// NSURL *
//}
+(instancetype)HK_URLWithString:(NSString *)URLString{
NSURL * url = [NSURL URLWithString:URLString];
if(url ==nil){
NSLog(@"空了");
}
return url;
}
@end
此时,我们在ViewController.h文件还是使用最初的代码,一个代码都不需要修改
- (void)viewDidLoad {
[super viewDidLoad];
NSURL * url =[NSURL URLWithString:@"http://www.baidu.com/中文"];
NSURLRequest * request =[NSURLRequest requestWithURL:url];
NSLog(@"%@",request);
}
我们就可以达到我们的目的,这种方式叫做方法欺骗。利用的就是runtime的HOOK。
这是因为我们修改了消息发送时候真正的方法实现。
我们在ViewController中调用URLWithString方法,实际运行的是HK_URLWithString,而在NSURL+HOOK.m文件中我们调用了URLWithString方法,实际运行的仍然是它本身,所以就不会不断循环,导致程序内存暴增,而卡死崩溃。那我们怎么解决呢?很简单,我们把NSURL+HOOK.m文件中的URLWithString替换成HK_URLWithString
#import "NSURL+HOOK.h"
#import
@implementation NSURL (HOOK)
+(void)load{
//获取两个Method
Method URLWithStr = class_getClassMethod(self, @selector(URLWithString:));
Method HKWithStr = class_getClassMethod(self, @selector(HK_URLWithString:));
//交换方法的IMP
method_exchangeImplementations(URLWithStr, HKWithStr);
}
//重写URLWithString?
//+(instancetype)URLWithString:(NSString *)URLString{
// NSURL *
//}
+(instancetype)HK_URLWithString:(NSString *)URLString{
NSURL * url = [NSURL HK_URLWithString:URLString];
if(url ==nil){
NSLog(@"空了");
}
return url;
}
@end
在运行,我们发现就可以达到我们所设想的目的。我们可以不需要修改原来项目中的代码,仅仅把NSURL+HOOK.h和NSURL+HOOK.m拖进项目中就可以实现了
2018-04-23 11:22:36.367259+0800 003-HOOK[1748:5624887] 空了
2018-04-23 11:22:36.367636+0800 003-HOOK[1748:5624887] { URL: (null) }
gitHub示例:https://github.com/Goddreamwt/iOS_HOOK.git