我们在使用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] <NSURLRequest: 0x60400000e6d0> { URL: (null) }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
那我们有没有办法改进呢?做下尝试
我们创建一个继承自NSURL的类,命名为HOOK,然后新建一个方法
#import <Foundation/Foundation.h>
@interface NSURL (HOOK)
+(instancetype)HK_URLWithString:(NSString *)URLString;
@end
- 1
- 2
- 3
- 4
- 5
- 6
- 7
#import "NSURL+HOOK.h"
@implementation NSURL (HOOK)
+(instancetype)HK_URLWithString:(NSString *)URLString{
NSURL * url = [NSURL URLWithString:URLString];
if(url ==nil){
NSLog(@"空了");
}
return url;
}
@end
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
此时我们需要在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] <NSURLRequest: 0x604000200480> { URL: (null) }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
那有没有更简洁的方式呢?可以利用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 <objc/runtime.h>
@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
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
此时,我们在ViewController.h文件还是使用最初的代码,一个代码都不需要修改
- (void)viewDidLoad {
[super viewDidLoad];
NSURL * url =[NSURL URLWithString:@"http://www.baidu.com/中文"];
NSURLRequest * request =[NSURLRequest requestWithURL:url];
NSLog(@"%@",request);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
我们就可以达到我们的目的,这种方式叫做方法欺骗。利用的就是runtime的HOOK。
但是我们发现程序并没有我们想象的顺利运行,而是卡死了
这是因为我们修改了消息发送时候真正的方法实现。
我们在ViewController中调用URLWithString方法,实际运行的是HK_URLWithString,而在NSURL+HOOK.m文件中我们调用了URLWithString方法,实际运行的仍然是它本身,所以就不会不断循环,导致程序内存暴增,而卡死崩溃。那我们怎么解决呢?很简单,我们把NSURL+HOOK.m文件中的URLWithString替换成HK_URLWithString
#import "NSURL+HOOK.h"
#import <objc/runtime.h>
@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
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
在运行,我们发现就可以达到我们所设想的目的。我们可以不需要修改原来项目中的代码,仅仅把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] <NSURLRequest: 0x604000019110> { URL: (null) }
- 1
- 2