博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
IOS网络访问之NSURLConnection
阅读量:4966 次
发布时间:2019-06-12

本文共 10744 字,大约阅读时间需要 35 分钟。

IOS网络访问主要建立在http协议上

IOS提供了几个重要的对象完成http请求响应

NSURLRequest:代表一个请求,通过NSURLRequest可以设置请求的URL地址以及缓存策略

NSMutableURLRequest:NSURLRequest的子类,可以方便地设置请求头的各种信息以及请求方式

NSURLConnection:网络访问对象,可以通过同步或者异步的方式发送请求

- (void)viewDidLoad{    [super viewDidLoad];    // Do any additional setup after loading the view, typically from a nib.        //访问的URL    NSString *str = @"http://www.baidu.com/";    //对URL进行编码    str = [str stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];        //生成NSURLRequest,timeoutInterval表示超时时间,默认60秒    NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:str] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60];    NSURLResponse *resp = [[NSURLResponse alloc] init];    NSError *error = [[NSError alloc] init];    NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&resp error:&error];    NSLog(@"%@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);}

 

上面代码访问了百度首页,如果URL中包含中文字符必须先经过编码

其中NSURLRequest初始化方法中的cachePolicy表示缓存策略,它可以设置成以下的值

NSURLRequestUseProtocolCachePolicy  根据response中的Cache-Control字段判断缓存是否有效,如果缓存有效则使用缓存数据否则重新从服务器请求 

NSURLRequestReloadIgnoringLocalCacheData   不使用缓存,直接从服务器请求数据

NSURLRequestReloadIgnoringCacheData = NSURLRequestReloadIgnoringLocalCacheData  以上一个值意义相同

NSURLRequestReturnCacheDataElseLoad  如果缓存有效则使用缓存否则从服务器请求数据

NSURLRequestReturnCacheDataDontLoad  如果缓存有效则使用缓存否则请求失败

 

异步请求

sendSynchronousRequest使用的是同步方法访问网络,会阻塞主线程,一般我们常用异步方式访问网络,可以通过多种方式实现异步请求

首先我们写个简短的服务器代码,接收请求参数然后输出

//iostest.php

方式一:我们可以使用多线程,将上面同步请求的代码放在多线程环境下,这样就不会阻塞主线程

- (void)viewDidLoad{    [super viewDidLoad];    [self performSelectorInBackground:@selector(connection) withObject:nil];}-(void)connection {    //访问的URL    NSString *str = @"http://localhost/iostest.php";    //对URL进行编码    str = [str stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];        NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];    //设置url    request.URL = [NSURL URLWithString:str];    //缓存策略    request.cachePolicy = 0;    //设置请求方式    request.HTTPMethod = @"POST";    //设置请求体    request.HTTPBody = [@"name=zanglitao&gender=male" dataUsingEncoding:NSUTF8StringEncoding];            NSURLResponse *resp = [[NSURLResponse alloc] init];    NSError *error = [[NSError alloc] init];    NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&resp error:&error];        NSLog(@"%@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);}

输出:zanglitao|male

 

方式二:使用NSURLConnection的类方法sendAsynchronousRequest

- (void)viewDidLoad{    [super viewDidLoad];    // Do any additional setup after loading the view, typically from a nib.        //访问的URL    NSString *str = @"http://localhost/iostest.php";    //对URL进行编码    str = [str stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];        NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];    //设置url    request.URL = [NSURL URLWithString:str];    //缓存策略    request.cachePolicy = 0;    //设置请求方式    request.HTTPMethod = @"POST";    //设置请求体    request.HTTPBody = [@"name=zanglitao&gender=male" dataUsingEncoding:NSUTF8StringEncoding];        [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {        NSLog(@"%@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);    }];    }

 

方式三:通过NSURLConnectionDataDelegate代理实现,这种方式较为繁琐,优点是可以获得请求进度

@interface ZLTViewController () {    NSMutableData *_data;    int _length;}@end@implementation ZLTViewController- (void)viewDidLoad{    [super viewDidLoad];    // Do any additional setup after loading the view, typically from a nib.        //访问的URL    NSString *str = @"http://g.hiphotos.baidu.com/image/h%3D800%3Bcrop%3D0%2C0%2C1280%2C800/sign=eaef18bb830a19d8d403890503c1e1f9/bd315c6034a85edfabe1bf294a540923dd54754e.jpg";    //对URL进行编码    str = [str stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];        NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:str]];    //初始化NSURLConnection时设置代理对象    NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];    //开始请求    [conn start];}//获得请求- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {    _data = [[NSMutableData alloc] init];    NSHTTPURLResponse *resp = (NSHTTPURLResponse *)response;        //取得响应头    NSDictionary *headFields = [resp allHeaderFields];//取得响应数据长度    _length = [headFields[@"Content-Length"] integerValue];    NSLog(@"请求数据大小:%ld",_length);}- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {    [_data appendData:data];    float percent = (float)[_data length]/_length * 100;    NSLog(@"当前进度:%f",percent);}- (void)connectionDidFinishLoading:(NSURLConnection *)connection {    NSLog(@"请求结束");}- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {    NSLog(@"请求失败");}

以上代码访问了互联网的一张图片,当获得响应时didReceiveResponse会被触发,我们可以在这里通过Content-Length字段获取响应数据的大小,然后接收数据时didReceiveData会不断被调用

输出:

请求数据大小:6542

当前进度:59.202080

当前进度:79.807404

当前进度:100.000000

请求结束

 

下载文件

当文件很大的时候我们使用NSURLConnection直接下载是不现实的,常用方法是每次请求一小段数据,一次一次的下载

请求头中有个参数Range可以用来控制访问的数据的范围,比如100个字节的数据,我们可以通过设定Range:Bytes=20-80 下载20到80的字节(使用Range我们也可以实现多线程下载)

除了GET和POST,NSURLRequest还提供了HEAD的请求方式,可以仅请求头信息来获取数据的长度

注意:NSURLRequest不能使用缓存,因为我们会多次请求相同的url,如果使用了缓存每次都会请求第一次请求的数据

@interface ZLTViewController () {    //储存请求来的数据    NSMutableData *_data;    //数据总长度    int _length;}@end@implementation ZLTViewController- (void)viewDidLoad{    [super viewDidLoad];    // Do any additional setup after loading the view, typically from a nib.        _data = [NSMutableData data];    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{        [self download];    });}//下载-(void)download {    long long length = [self getFileTotalLength];        long long start = 0;    long long end = 0;        while (start < length) {        end = start + 1024 - 1;        if (end >= length) {            end = length - 1;        }        [self downFilefrom:start end:end];        NSLog(@"%lld,%lld,%lld",length,start,end);        start += 1024;    }            __weak UIView *weakView = self.view;    dispatch_async(dispatch_get_main_queue(), ^{        UIImage *image = [UIImage imageWithData:_data];        UIImageView *imageview = [[UIImageView alloc] initWithImage:image];        [weakView addSubview:imageview];    });}//获得文件url-(NSURL *)getURL {    NSString *urlStr = @"http://g.hiphotos.baidu.com/image/pic/item/8d5494eef01f3a290bed8dc49a25bc315c607c96.jpg";    urlStr = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];        return [NSURL URLWithString:urlStr];}//获取文件大小- (long long)getFileTotalLength {    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[self getURL]];    request.HTTPMethod = @"HEAD";        NSURLResponse *response = [[NSURLResponse alloc] init];    NSError *error = [[NSError alloc] init];    [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];        return response.expectedContentLength;}//下载指定区域的文件- (void)downFilefrom:(long long)start end:(long long)end {    NSString *range = [NSString stringWithFormat:@"Bytes=%lld-%lld",start,end];        //缓存策略需要使用NSURLRequestReloadIgnoringCacheData,否则每次都会请求第一次请求的数据(0-1023)    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[self getURL] cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:5.0f];    [request setValue:range forHTTPHeaderField:@"Range"];            NSURLResponse *response = [[NSURLResponse alloc] init];    NSError *error = [[NSError alloc] init];        NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];        //数据写入文件    [self appendDataToFile:data];    //数据写入NSData    [_data appendData:data];}-(void)appendDataToFile:(NSData *)data {    NSString *url = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];    url = [url stringByAppendingPathComponent:@"1.jpg"];        NSFileHandle *handle = [NSFileHandle fileHandleForWritingAtPath:url];    if (handle) {        [handle seekToEndOfFile];        [handle writeData:data];        [handle closeFile];    } else {        [data writeToFile:url atomically:YES];    }}@end

 

 

上传文件

首先我们看看使用浏览器上传文件时请求头

这里有两个关键的字段:Content-Length和Content-Type

Content-Length表示请求体字节长度,Content-Type前面是固定格式multipart/form-data; boundary=---------------------------,后面那串数字由浏览器随机生成最为boundary,我们也可以指定为任意的字符串值

 

请求体:

请求体开始是--加上请求头中boundary=后面的内容,然后跟着一个\n换行

第二行中name="file"表示表单中文件使用了file这个name(所以服务器需要通过file接收数据) filename指定了上传文件的文件名,然后跟着一个\n换行

第三行表示上传文件的MIMETYPE,最后跟着两个\n(如果漏了一个\n会上传失败)

第五行开始是文件的内容,文件结束后跟着一个\n(最容易遗忘的一个\n)

最后是-- + 请求头中boundary=后面的内容 + --,不要忘了后面还有两个\n

 

所以我们写代码时主要注意点在两处,一个是设置请求头的两个参数,一个是请求体的拼接,具体代码如下

//自定义一个boundary#define boundary @"zanglitao"@interface ZViewController()@end@implementation ZViewController-(void)viewDidLoad {    [super viewDidLoad];    [self upload];}-(void)upload {    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"http://localhost/iostest.php"]];    //必须使用POST    request.HTTPMethod = @"POST";        NSData *data = [self getDataBody];    //设置请求头    [request setValue:[NSString stringWithFormat:@"%d",data.length] forHTTPHeaderField:@"Content-Length"];    [request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@",boundary] forHTTPHeaderField:@"Content-Type"];    //设置请求体    request.HTTPBody = data;            [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {        if (connectionError) {            NSLog(@"%@",[connectionError localizedDescription]);        } else {            NSLog(@"%@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);        }            }];}//获取请求体内容-(NSData *)getDataBody {    NSMutableData *data = [NSMutableData data];        NSString *top = [NSString stringWithFormat:@"--%@\nContent-Disposition: form-data; name=\"file\"; filename=\"1.png\"\nContent-Type: image/png\n\n",boundary];        NSString *bottom = [NSString stringWithFormat:@"\n--%@--\n\n",boundary];        NSData *content = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"1" ofType:@"png"]];        [data appendData:[top dataUsingEncoding:NSUTF8StringEncoding]];    [data appendData:content];    [data appendData:[bottom dataUsingEncoding:NSUTF8StringEncoding]];    return data;}@end

 

转载于:https://www.cnblogs.com/zanglitao/p/4072229.html

你可能感兴趣的文章
一种反射的方式
查看>>
android环境搭建
查看>>
写javascript是前台和后的内容的区别
查看>>
java旅程(二) 基本语法
查看>>
仓储repository概念
查看>>
freemarker<一>
查看>>
程序员的数学--排列组合(0)
查看>>
c语言 rand() 随机函数
查看>>
覆盖索引有何用?
查看>>
mobile base
查看>>
linux 内核配置 library routines
查看>>
docker应用,后端服务出现OOM情况排查
查看>>
寄存器
查看>>
bzoj1690/poj3621[Usaco2007 Dec]奶牛的旅行
查看>>
Linux设备驱动之中断支持及中断分层
查看>>
vue视频学习笔记02
查看>>
ECMAScript迭代语句
查看>>
Web服务器(容器)请求常见的错误及其解决方法
查看>>
在 Linux 系统中安装Load Generator ,并在windows 调用
查看>>
活动图
查看>>