最近在研究 AFNetworking 源码,发现了一些原先没掌握好的东东,整理下…
NSURL 对于 NSURL
的理解,原先指示停留在将 NSString
转换为 NSURL
。今天细看文档,发现好多好用的功能,原先还自己封装来获取 URL 后缀,现在看来是真没文化啊。
0.经典用法
1
2
NSURL *url1 = [NSURL URLWithString:@"http://www.baidu.com/img/bd_logo1.png"];
NSURL *url2 = [NSURL URLWithString:@"/img/bd_logo1.png" relativeToURL:[NSURL URLWithString:@"http://www.baidu.com"]];
1.加载项目中本地网页
1
2
NSString *urlPath = [[NSBundle mainBundle] pathForResource:@"404" ofType:@"html"];
NSURL *url = [NSURL URLWithString:urlPath];
2.获取扩展名
1
2
NSURL *url = [NSURL URLWithString:@"http://www.iyiming.me/hello.png"];
NSString *pathExtension = [url pathExtension];//扩展名 png
3.获取组成部分
1
2
NSURL *url = [NSURL URLWithString:@"http://www.iyiming.me/index.htm"];
NSArray *pathComponentsArray = [url pathComponents];//所有组成部分 [/,index.htm]
4.获取主机
1
2
NSURL *url = [NSURL URLWithString:@"http://www.iyiming.me/index.htm"];
NSString *host = [url host];//主机 www.iyiming.me
5.获取端口号
1
2
NSURL *url = [NSURL URLWithString:@"http://www.iyiming.me:80/index.htm"];
NSNumber *port = [url port];//端口号 80
6.获取查询参数
1
2
NSURL *url = [NSURL URLWithString:@"http://www.iyiming.me:80/index.htm?key1=value1&key2=value2"];
NSString *query = [url query];//查询参数 key1=value1&key2=value2
7.获取协议名称
1
2
NSURL *url = [NSURL URLWithString:@"http://www.iyiming.me:80/index.htm?key1=value1&key2=value2"];
NSString *scheme = [url scheme];//协议 http
8.获取锚定位
1
2
NSURL *url = [NSURL URLWithString:@"http://www.iyiming.me:80/index.htm#jumpLocation"];
NSString *fragment = [url fragment];//锚定位 jumpLocation
9.获取用户名
1
2
NSURL *url = [NSURL URLWithString:@"ftp://yiming@www.iyiming.me"];
NSString *user = [url user];//用户名 yiming
NSMutableURLRequest NSURLMutableRequest
是 NSURLRequest
的子类,名如其类,它是可扩充的NSURLRequest
。
0.缓存1
2
3
4
5
6
7
8
enum
{
NSURLRequestUseProtocolCachePolicy = 0,
NSURLRequestReloadIgnoringLocalCacheData = 1,
NSURLRequestReturnCacheDataElseLoad = 2,
NSURLRequestReturnCacheDataDontLoad = 3,
};
typedef NSUInteger NSURLRequestCachePolicy;
关于缓存的介绍 ,可以看看下面这篇博客,写的很是详细:
iOS 开发之缓存(一):内存缓存
1.设置请求超时时间
设置 timeoutInterval
属性的就 OK 啦。
2.GET 请求
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
#pragma mark -获取参数字符串
- (NSString *) parametersStr:(NSDictionary *) parametersDic
{
NSMutableArray *parametersArray = [[NSMutableArray alloc] init];
for (id key in parametersDic.allKeys) {
if ([key isKindOfClass:[NSString class]]) {
id value = parametersDic[key];
NSString *parameterStr = [NSString stringWithFormat:@"%@=%@",key,value];
[parametersArray addObject:parameterStr];
}
}
NSString *parametersStr = [parametersArray componentsJoinedByString:@"&"];
return parametersStr;
}
#pragma mark -GET Request
- (NSURLRequest *) GET:(NSString *)URLString parameters:(NSDictionary *) parametersDic
{
NSString *parametersStr = [self parametersStr:parametersDic];//请求参数字符串
NSString *requestURLStr = [NSString stringWithFormat:@"%@?%@",URLString,parametersStr];//请求URL字符串
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:requestURLStr]];
//设置请求头部
////设置ContentType
[request addValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
//设置Content-length
[request addValue:[NSString stringWithFormat:@"%lu",(unsigned long)[parametersStr length]] forHTTPHeaderField:@"Content-Length"];
//设置请求类型 GET
[request setHTTPMethod:@"GET"];
return request;
}
3.POST 请求
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#pragma mark -POST Request
- (NSURLRequest *) POST:(NSString *)URLString parameters:(NSDictionary *) parametersDic
{
NSString *parametersStr = [self parametersStr:parametersDic];//请求参数字符串
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:URLString]];
//设置请求头部
////设置ContentType
[request addValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
//设置Content-length
[request addValue:[NSString stringWithFormat:@"%lu",(unsigned long)[parametersStr length]] forHTTPHeaderField:@"Content-Length"];
//设置请求类型 GET
[request setHTTPMethod:@"POST"];
//设置请求Body
[request setHTTPBody:[parametersStr dataUsingEncoding:NSUTF8StringEncoding]];
return request;
}
4.发送图片等多媒体数据
未完成
NSURLConnection 0.同步加载数据
1
2
3
4
5
6
7
8
9
NSURLRequest *request = [self GET:urlStr parameters:parametersDic];
NSError *error = nil;
NSURLResponse *response = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if (!error) {
NSString *dataStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"获取的字符串 %@",dataStr);
}
1.异步加载数据
1.1 +connectionWithRequest:delegate:
1
2
NSURLRequest *request = [self GET:urlStr parameters:parametersDic];
[NSURLConnection connectionWithRequest:request delegate:self];
1.2 -initWithRequest:delegate:
1
[[NSURLConnection alloc] initWithRequest:request delegate:self];
1.3 -initWithRequest:delegate:startImmediately:
startImmediately
参数为 YES
时,会立刻执行。如果 startImmediately
参数为 NO
时,将不会在当前 RunLoop 中运行,需要手动调用 scheduleInRunLoop:forMode:
方法。不调用scheduleInRunLoop:forMode:
方法,也可以调用 start
方法来执行,此时的RunLoop 是当时的 RunLoop。关于 RunLoop 可以参考这篇文章
1
2
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
[connection start];
1.4 -sendAsynchronousRequest:queue:completionHandler:
queue 参数是指 completionHandler Block 执行所在的队列
1
2
3
4
5
6
7
8
9
10
11
12
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
if (!connectionError) {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSString *dataStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"获取的字符串 %@",dataStr);
});
});
}else{
NSLog(@"error:%@",connectionError.localizedDescription);
}
}];
2.取消 Connection
调用 cancel 方法,如果取消之后,还想继续建立连接,需要重新实例化 connection 对象
NSURLConnectionDelegate 这个协议经常用到,但是不知道它是用来干啥的。相关资料也很少,只好查看官方文档
NSURLConnectionDelegate
是配合 NSURLConnectionDataDelegate
、NSURLConnectionDownloadDelegate
协议使用的。常见的connection:didFailWithError:
方法就属于 NSURLConnectionDelegate
。
NSURLConnectionDelegate
中声明的方法,有些方法都已经废除了,见下图:
0.-connection:willSendRequestForAuthenticationChallenge:
Tells the delegate that the connection will send a request for an authentication challenge. 告诉协议,连接(connection)将会为身份认证询问发送一个请求
1.- (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection *)connection
URL 加载者是否使用凭证存储来认证连接 Sent to determine whether the URL loader should use the credential storage for authenticating the connection.
如何返回 NO,连接不会自动询问凭证存储,不会存储凭证,然而,在connection:didReceiveAuthenticationChallenge
方法中,更具需要可以自己实现询问凭证存储,存储凭证。
在 iOS 7 和 OS X v10.9之前,实现connection:willSendRequestForAuthenticationChallenge:
方法不会调用connectionShouldUseCredentialStorage:
方法。也就是说,在以后的操作系统(iOS 7 和 OS X v10.9后)中,实现connection:willSendRequestForAuthenticationChallenge:
方法会调用connectionShouldUseCredentialStorage:
方法。
2.例子:实现访问无线路由器设置页面
一般无线路由器设置了密码,访问路由器设置页面会出现如下图页面(有的是http://192.168.0.1 或者是http://192.168.1.1 ):
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
37
38
39
40
41
42
43
44
45
46
47
//步骤一 建立连接
NSURLRequest *request = [self POST:@"http://192.168.0.1" parameters:nil];
connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
[connection start];
//步骤二 实现NSURLConnectionDelegate
#pragma mark -NSURLConnectionDataDelegate
- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
if ([challenge previousFailureCount] == 0) {
NSLog(@"received authentication challenge");
NSURLCredential *newCredential = [NSURLCredential credentialWithUser:@"这个地方输入用户名"
password:@"这个地方输入密码"
persistence:NSURLCredentialPersistenceForSession];
NSLog(@"credential created");
[[challenge sender] useCredential:newCredential forAuthenticationChallenge:challenge];
NSLog(@"responded to authentication challenge");
}else {
NSLog(@"previous authentication failure");
}
}
//步骤三 实现NSURLConnectionDataDelegate
- (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[responseData setLength:0];
NSLog(@"接收响应");
}
- (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[responseData appendData:data];
NSLog(@"接收数据...");
}
- (void) connectionDidFinishLoading:(NSURLConnection *)connection
{
NSString *newStr = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
//简单测试 用于显示路由器设置页面
UIWebView *mainWebView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 400)];
[mainWebView loadHTMLString:newStr baseURL:[NSURL URLWithString:@"http://192.168.0.1"]];
[self.view addSubview:mainWebView];
NSLog(@"完成 %@",newStr);
}
NSURLConnectionDataDelegate 未完成
参考文章
苹果官方文档:NSURL 苹果官方文档:NSMutableURLRequest 苹果官方文档:NSURLConnection iOS 开发中级:HTTP 请求 GET POST 网络编程实现