iOS9引入了新特性App Transport Security (ATS)。新特性要求App内访问的网络必须使用HTTPS协议。但是现在公司的项目使用的是HTTP协议,使用私有加密方式保证数据安全。现在也不能马上改成HTTPS协议传输。
最终找到以下解决办法:
在Info.plist中添加NSAppTransportSecurity类型Dictionary。
在NSAppTransportSecurity下添加NSAllowsArbitraryLoads类型Boolean,值设为YES,如图:
下面来介绍iOS开发中网络编程实现方案:NSURLConnection
苹果原生(自带)的网络编程API:NSURLConnection
NSURL:请求地址
NSURLRequest:封装一个请求,保存发给服务器的全部数据,包括:一个NSURL对象、请求方法、请求头、请求体等等
NSMutableURLRequest:NSURLRequest的子类
NSURLConnection
负责发送请求,建立客户端和服务器的连接
发送NSURLRequest的数据给服务器,并收集来自服务器的响应数据
NSURLConnection的使用步骤
1. 创建一个NSURL对象,设置请求路径
2. 传入NSURL创建一个NSURLRequest对象,设置请求头和请求体(可不用设置)
3. 使用NSURLConnection发送NSURLRequest
下面是向网络请求一张图片数据的代码:
- (void)viewDidLoad {
[super viewDidLoad];
// 创建url
NSURL *url = [NSURL URLWithString:@"http://a2.att.hudong.com/38/59/300001054794129041591416974.jpg"];
// 创建请求
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// 建立连接,并异步发送请求(这里就不赘述原因了)
NSOperationQueue *<span style="color:#3333FF;">queue</span> = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:request queue:<span style="color:#3333FF;">queue</span> completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
NSLog(@"%lu---%@", data.length, [NSThread currentThread]);
}];
}
打印结果:
注意:在block中有数据返回,且数据长度为79064,但是block中的执行代码是在number = 2的线程中,因为之前创建的一个新线程。在block中获得数据后,应该在主线程刷新\显示数据,所以这里不能是子线程,只能是主线程,queue的参数应该传:[NSOperationQueue mainQueue]。
此时运行结果:
总结:NSURLConnection发送请求方式:
1.同步请求
+ (NSData *)sendSynchronousRequest:(NSURLRequest *)request returningResponse:(NSURLResponse **)response error:(NSError **)error;
2.异步请求:根据对服务器返回数据的处理方式的不同,又可以分为2种
1)block回调
+(void)sendAsynchronousRequest:(NSURLRequest*)request queue:(NSOperationQueue*) queue
completionHandler:(void (^)(NSURLResponse* response, NSData* data,NSError* connectionError)) handler;
2)代理
- (id)initWithRequest:(NSURLRequest*)request delegate:(id)delegate;
+(NSURLConnection*)connectionWithRequest:(NSURLRequest *)requestdelegate:(id)delegate;
- (id)initWithRequest:(NSURLRequest*)request delegate:(id)delegate startImmediately:(BOOL)startImmediately;
在这种情况下,需要调用start方法开始发送请求
- (void)start;
成为NSURLConnection的代理,最好遵守
NSURLConnectionDataDelegate协议
用上面请求图片的例子,使用代理的方法请求:
- (void)viewDidLoad {
[super viewDidLoad];
// 创建url
NSURL *url = [NSURL URLWithString:@"http://a2.att.hudong.com/38/59/300001054794129041591416974.jpg"];
// 创建请求
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
// 设置请求超时
request.timeoutInterval = 10.0;
request.HTTPMethod = @"GET";// 默认GET
// 建立连接,发送请求(异步)
// NSURLConnection *conn = [NSURLConnection connectionWithRequest:request delegate:self];
// NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];
// NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:<span style="color:#ff0000;">YES</span>];
// 上面三种方式发送异步请求是一样的,不需要调用start方法即可发送异步请求。
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
[conn start];// 这种方式需要调用start方法,发送异步请求操作
NSLog(@"请求已经发出");
}
#pragma mark -NSURLConnectionDataDelegate
/**
* 开始接收到服务器的响应时调用
*/
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
self.data = [NSMutableData data];
NSLog(@"开始接收数据- %@", [NSThread currentThread]);
}
/**
* 接收到服务器返回的数据时调用(服务器返回的数据比较大时会调用多次)
*/
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[self.data appendData:data];
NSLog(@"接收到服务器返回的数据时调用- %@", [NSThread currentThread]);
}
/**
* 服务器返回的数据完全接收完毕后调用
*/
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSLog(@"完全接收完毕--%lu--%@", self.data.length, [NSThread currentThread]);
}
/**
* 请求出错时调用(比如请求超时)
*/
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog(@"请求出错");
}
当控制器view加载完毕后,会打印出:请求已经发出。说明发送的请求是异步的,没有阻塞主线程。请求之后会回调代理方法,代理方法是在主线程的返回数据的。
运行结果:
NSMutableURLRequest
- (void)setTimeoutInterval:(NSTimeInterval)seconds;
- (void)setHTTPMethod:(NSString*)method;
- (void)setHTTPBody:(NSData*)data;
- (void)setValue:(NSString*)value forHTTPHeaderField:(NSString*)field;
NSString *urlStr = [@"http://192.168.1.102:8080/MJServer/login?name=shx&pwd=123" stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *url = [NSURLURLWithString:urlStr];
NSMutableURLRequest*request = [NSMutableURLRequestrequestWithURL:url];
NSString*urlStr = @"http://192.168.1.102:8080/MJServer/login";
NSURL *url= [NSURLURLWithString:urlStr];
NSMutableURLRequest*request = [NSMutableURLRequestrequestWithURL:url];
request.HTTPMethod = @"POST";
// 请求体
NSString *bodyStr = @"name=shx&pwd=123";
request.HTTPBody = [bodyStr dataUsingEncoding:NSUTF8StringEncoding];// 编码
iOS 7之后NSURLConnection就过期了,新出了NSURLSession替代NSURLConnection,用法差不多,如下(只是简单的使用NSURLSession):
- (void)viewDidLoad {
[super viewDidLoad];
// 创建url
NSURL *url = [NSURL URLWithString:@"http://a2.att.hudong.com/38/59/300001054794129041591416974.jpg"];
// 创建请求
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
// 设置请求超时
request.timeoutInterval = 10.0;
request.HTTPMethod = @"GET";// 默认GET
// 1.创建NSURLSession
NSURLSession *session = [NSURLSession sharedSession];
// 2.利用NSURLSession创建Task
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
/*
data: 服务器返回给我们的数据
response : 响应头
error: 错误信息
*/
NSLog(@"%lu-%@", data.length, [NSThread currentThread]);
}];
// 3.执行Task
[task resume];
}
运行结果:
注意:block也是在子线程中返回数据