iOS学习笔记12-网络(一)NSURLConnection
一、网络请求
在网络开发中。须要了解一些经常使用的请求方法:
- GET请求:get是获取数据的意思,数据以明文在URL中传递,受限于URL长度,所以数据传输量比較小。
- POST请求:post是向server提交数据的意思。提交的数据以实际内容形式存放到消息头中进行传递,无法在浏览器url中查看到,大小没有限制。
- HEAD请求:请求头信息,并不返回请求数据体,而仅仅返回请求头信息,经常使用用于在文件下载中取得文件大小、类型等信息。
二、NSURLConnection
NSURLConnection是苹果提供的原生网络訪问类,可是苹果非常快会将其废弃。且由NSURLSession(iOS7以后)来替代。眼下使用最广泛的第三方网络框架AFNetworking最新版本号已弃用了NSURLConnection,那我们学习它还有什么用呢?
* 首先,苹果弃用它还是须要时间的,最起码到iOS10之后。
* 如今另一些老项目会使用NSURLConnection。特别是2013年之前的项目,用户量基础还是非常大的;
* 另外,不得不承认,有些公司还在用相似ASI这些经典的网络框架。所以还是非常有必要学习NSURLConnection的。
让我们来首先了解几个类:
1. NSURL:请求地址,定义一个网络资源路径
NSURL *url = [NSURL URLWithString:@"协议://主机地址/路径?參数&參数"];
解释例如以下:
- 协议:不同的协议,代表着不同的资源查找方式、资源传输方式,比方经常使用的
http
。ftp
等 - 主机地址:存放资源的主机的IP地址(域名)
- 路径:资源在主机中的详细位置
- 參数:參数可有可无。也能够多个。如果带參数的话,用“?”号后面接參数,多个參数的话之间用&隔开
2.NSURLRequest:请求,依据前面的NSURL建立一个请求
NSURLRequest *request = [NSURLRequest requestWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:15.0];
參数解释例如以下:
url
:资源路径cachePolicy
:缓存策略(不管使用哪种缓存策略,都会在本地缓存数据),类型为枚举类型,取值例如以下:
NSURLRequestUseProtocolCachePolicy = 0 //默认的缓存策略,使用协议的缓存策略
NSURLRequestReloadIgnoringLocalCacheData = 1 //每次都从网络载入
NSURLRequestReturnCacheDataElseLoad = 2 //返回缓存否则载入。非常少使用
NSURLRequestReturnCacheDataDontLoad = 3 //仅仅返回缓存。没有也不载入。非常少使用
timeoutInterval
:超时时长。默认60s
另外,还能够设置其他一些信息,比方请求头,请求体等等。例如以下:
NSMutableURLRequest *request =
[NSMutableURLRequest requestWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:15.0];
// 告诉server数据为json类型
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
// 设置请求体body(json类型的数据)
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:@{@"userid":@"123456"}
options:NSJSONWritingPrettyPrinted
error:nil];
request.HTTPBody = jsonData;
注意,上面的request是
NSMutableURLRequest
,就可以变类型
3.NSURLResponse:请求结果响应,连接成功后server会返回的响应
- 该类不用我们创建。连接后server返回的。里面包括了一些响应信息
以下我们来发个完整的网络请求:
#pragma mark 发送数据请求
- (void)sendRequest{
NSString *urlStr = [NSString stringWithFormat:@"http://192.168.1.208/FileDownload.aspx?file=%@",_textField.text];
//注意对于url中的中文是无法解析的。须要进行url编码(指定编码类型为utf-8)
//另外注意url解码使用stringByRemovingPercentEncoding方法
urlStr = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
//创建url链接,该链接是下载文件
NSURL *url = [NSURL URLWithString:urlStr];
//创建请求
NSURLRequest *request = [NSURLRequest requestWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:15.0f];
//创建连接,设置请求。以及设置代理
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
//启动连接,用start启动的连接都是异步请求
[connection start];
}
要得到请求的数据,须要实现NSURLConnection的代理方法:
#pragma mark - 连接代理方法
#pragma mark 開始响应
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
_data = [[NSMutableData alloc] init];
_progressView.progress = 0;
//通过响应头中的Content-Length取得整个响应的总长度
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
NSDictionary *httpResponseHeaderFields = [httpResponse allHeaderFields];
_totalLength = [[httpResponseHeaderFields objectForKey:@"Content-Length"] longLongValue];
}
#pragma mark 接收响应数据(依据响应内容的大小此方法会被反复调用)
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
//连续接收数据
[_data appendData:data];
//更新进度
[self updateProgress];
}
#pragma mark 数据接收完毕
- (void)connectionDidFinishLoading:(NSURLConnection *)connection{
//数据接收完保存文件(注意苹果官方要求:下载数据仅仅能保存在缓存文件夹)
NSString *savePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
savePath = [savePath stringByAppendingPathComponent:_textField.text];
[_data writeToFile:savePath atomically:YES];
}
#pragma mark 请求失败
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
//如果连接超时或者连接地址错误可能就会报错
}
但这样每次都要去实现这些代理,感觉十分麻烦,不用怕。NSURLConnection有简化方法。这也是我们用的最多得。
typedef void (^CompletionBlock)(NSURLResponse*, NSData*, NSError*);
/* 发送一个异步请求 */
+ (void)sendAsynchronousRequest:(NSURLRequest *)request /*请求*/
queue:(NSOperationQueue *)queue /* 连接所在线程队列 */
completionHandler:(CompletionBlock)completion;/* 请求回调 */
/* 发送一个同步请求 */
+ (void)sendSynchronousRequest:(NSURLRequest *)request /*请求*/
queue:(NSOperationQueue *)queue /* 连接所在线程队列 */
completionHandler:(CompletionBlock)completion;/* 请求回调 */
这样我们就不用实现代理方法了。以下是简化方法的使用实例:
#pragma mark 发送数据请求
- (void)sendRequest{
NSString *urlStr = [NSString stringWithFormat:@"%@",kURL];
urlStr = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
//创建url链接
NSURL *url = [NSURL URLWithString:urlStr];
/*创建可变请求*/
NSMutableURLRequest *requestM = [NSMutableURLRequest requestWithURL:url cachePolicy:0 timeoutInterval:5.0f];
[requestM setHTTPMethod:@"POST"];//设置位post请求
//创建post參数
NSString *bodyDataStr = [NSString stringWithFormat:@"userName=%@&password=%@",_userName,_password];
NSData *bodyData = [bodyDataStr dataUsingEncoding:NSUTF8StringEncoding];
[requestM setHTTPBody:bodyData];
//发送一个异步请求
[NSURLConnection sendAsynchronousRequest:requestM
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (!error) {
//载入数据
[self loadData:data];
//刷新表格
[_tableView reloadData];
}
}];
}
三、进阶-文件分段下载
实际开发文件下载的时候。不管是通过代理方法还是静态方法运行请求和响应,我们都会分批请求数据,而不是一次性请求数据。
如果一个文件有1G,那么仅仅要每次请求1M的数据,请求1024次也就下载完了。
那么怎样让server每次仅仅返回1M的数据呢?
- 在网络开发中能够在请求的头文件里设置一个range信息。它代表请求数据的大小。
- 在WEB开发中我们还有另一种请求方法“HEAD”,通过这样的请求server仅仅会响应头信息。其他数据不会返回给client,这样一来整个数据的大小也就能够得到了。
首先我们须要先获取要下载的文件大小:
#pragma mark 取得文件大小
- (long long)getFileTotlaLength:(NSString *)fileName{
NSURL *url = [self getDownloadUrl:fileName];//获取URL,这种方法我就不列出来了
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
cachePolicy:NSURLRequestReloadIgnoringCacheData
timeoutInterval:5.0f];
//设置为头信息请求
[request setHTTPMethod:@"HEAD"];
NSURLResponse *response;
NSError *error;
//注意这里使用了同步请求,直接将文件大小返回
[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
//取得内容长度
return response.expectedContentLength;
}
我们还须要封装一个下载指定数据大小的请求:
#pragma mark 下载指定块大小的数据
- (void)downloadFile:(NSString *)fileName startByte:(long long)start endByte:(long long)end{
NSString *range = [NSString stringWithFormat:@"Bytes=%lld-%lld",start,end];
NSURL *url = [self getDownloadUrl:fileName];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
cachePolicy:NSURLRequestReloadIgnoringCacheData
timeoutInterval:5.0f];
//通过请求头设置数据请求范围
[request setValue:range forHTTPHeaderField:@"Range"];
NSURLResponse *response = nil;
NSError *error = nil;
//注意这里使用同步请求,避免文件块追加顺序错误
NSData *data = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response
error:&error];
if(!error){
[self fileAppend:[self getSavePath:fileName] data:data];
}
}
最后我们来下载整个文件:
#pragma mark 异步下载文件
- (void)downloadFileAsync{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self downloadFile];
});
}
#pragma mark 文件下载,拼接每一个下载小文件
- (void)downloadFile{
// 获取要下载的文件总大小
_totalLength = [self getFileTotlaLength:_textField.text];
_loadedLength = 0;
long long startSize = 0;
long long endSize = 0;
//分段下载
while(startSize < _totalLength){
//kFILE_BLOCK_SIZE 宏定义的是分段下载的字节大小
endSize = startSize + kFILE_BLOCK_SIZE - 1;
if (endSize > _totalLength) {
endSize = _totalLength - 1;
}
[self downloadFile:_textField.text startByte:startSize endByte:endSize];
//更新进度
_loadedLength += (endSize - startSize) + 1;
[self updateProgress];
startSize += kFILE_BLOCK_SIZE;
}
}
四、进阶-文件上传
要实现文件上传,须要採用POST请求,请求数据类型必须为multipart/form-data
我们常见得请求数据类型有:
application/x-www-form-urlencoded
:默认值,发送前对全部发送数据进行url编码。支持浏览器訪问,通常文本内容提交经常使用这样的方式。multipart/form-data
:多部分表单数据,支持浏览器訪问,不进行不论什么编码,通经常使用于文件传输(此时传递的是二进制数据) 。text/plain
:普通文本数据类型。支持浏览器訪问。发送前当中的空格替换为“+”。可是不正确特殊字符编码。application/json
:json数据类型 。text/xml
:xml数据类型。
我们须要自己定制上传请求,以下为定制过程:
1. 上传请求头必须满足例如以下格式:
2. 请求体内容要求如以下格式:
--boundary
Content-Disposition:form-data;name=”表单控件名称”;filename=”上传文件名”
Content-Type:文件MIME Types
文件二进制数据;
--boundary--
至于上面上传文件的MIME Types类型,我列出几个经常使用的:
- *.gif文件 - image/gif
- *.html文件 - text/html
- *.jpg文件 - image/jpeg
- *.mov文件 - video/quicktime
- *.mp3文件 - audio/mpeg
- *.pdf文件 - application/pdf
- *.txt文件 - text/plain
- *.xml文件 - text/xml
- *.avi文件 - video/x-msvideo
以下为上传文件详细实例:
#pragma mark 上传文件
-(void)uploadFile{
NSString *fileName = _textField.text;
NSURL *url = [self getUploadUrl:fileName];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
cachePolicy:NSURLRequestReloadIgnoringCacheData
timeoutInterval:5.0f];
request.HTTPMethod = @"POST";
NSData *data = [self getHttpBody:fileName];
//通过请求头设置
NSString *lengthStr = [NSString stringWithFormat:@"%lu",(unsigned long)data.length];
[request setValue:lengthStr forHTTPHeaderField:@"Content-Length"];
NSString *typeStr = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",kBOUNDARY_STRING];
[request setValue:typeStr forHTTPHeaderField:@"Content-Type"];
//设置数据体
request.HTTPBody = data;
//发送异步请求
[NSURLConnection sendAsynchronousRequest:request
queue:[[NSOperationQueue alloc]init]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if(error){
NSLog(@"error:%@",connectionError.localizedDescription);
}
}];
}
#pragma mark 取得数据体
-(NSData *)getHttpBody:(NSString *)fileName{
NSMutableData *dataM = [NSMutableData data];
NSString *type = [self getMIMETypes:fileName];
//构建请求体body的顶部
NSMutableString *bodyTop = [NSMutableString string];
//宏kBOUNDARY_STRING就是boundary标示
[bodyTop appendFormat:@"--%@\n",kBOUNDARY_STRING];
[bodyTop appendFormat:@"Content-Disposition: form-data; name=\"file1\"; filename=\"%@\"\n",fileName];
[bodyTop appendFormat:@"Content-Type: %@\n\n",type];
//构建请求体body的底部
NSString *bodyBottom = [NSString stringWithFormat:@"\n--%@--",kBOUNDARY_STRING];
NSString *filePath = [[NSBundle mainBundle] pathForResource:fileName ofType:nil];
//构建请求体body中间的二进制上传数据
NSData *fileData = [NSData dataWithContentsOfFile:filePath];
//把顶部、数据、底部组合起来,形成body
[dataM appendData:[bodyTop dataUsingEncoding:NSUTF8StringEncoding]];
[dataM appendData:fileData];
[dataM appendData:[bodyBottom dataUsingEncoding:NSUTF8StringEncoding]];
return dataM;
}
有什么问题随时能够在下方评论提出!O(∩_∩)O哈。
iOS学习笔记12-网络(一)NSURLConnection的更多相关文章
- NodeJS学习笔记 (12)网络地址解析-url(ok)
模块概述 nodejs中,提供了url这个非常实用的模块,用来做URL的解析.在做node服务端的开发时会经常用到.使用很简单,总共只有3个方法. 正式讲解前,各位同学先把下面这个图记在心上(来自no ...
- iOS学习笔记-精华整理
iOS学习笔记总结整理 一.内存管理情况 1- autorelease,当用户的代码在持续运行时,自动释放池是不会被销毁的,这段时间内用户可以安全地使用自动释放的对象.当用户的代码运行告一段 落,开始 ...
- iOS学习笔记22-推送通知
一.推送通知 推送通知就是向用户推送一条信息来通知用户某件事件,可以在应用退到后台后,或者关闭后,能够通过推送一条消息通知用户某件事情,比如版本更新等等. 推送通知的常用应用场景: 一些任务管理APP ...
- iOS学习笔记13-网络(二)NSURLSession
在2013年WWDC上苹果揭开了NSURLSession的面纱,将它作为NSURLConnection的继任者.现在使用最广泛的第三方网络框架:AFNetworking.SDWebImage等等都使用 ...
- IOS学习笔记25—HTTP操作之ASIHTTPRequest
IOS学习笔记25—HTTP操作之ASIHTTPRequest 分类: iOS2012-08-12 10:04 7734人阅读 评论(3) 收藏 举报 iosios5网络wrapper框架新浪微博 A ...
- iOS学习笔记总结整理
来源:http://mobile.51cto.com/iphone-386851_all.htm 学习IOS开发这对于一个初学者来说,是一件非常挠头的事情.其实学习IOS开发无外乎平时的积累与总结.下 ...
- IOS学习笔记07---C语言函数-printf函数
IOS学习笔记07---C语言函数-printf函数 0 7.C语言5-printf函数 ------------------------- ----------------------------- ...
- IOS学习笔记06---C语言函数
IOS学习笔记06---C语言函数 -------------------------------------------- qq交流群:创梦技术交流群:251572072 ...
- IOS学习笔记02---语言发展概述,计算机语言简介.
IOS学习笔记02---语言发展概述,计算机语言简介. ------------------------------------------------------------------------ ...
随机推荐
- 老男孩全栈python学习进程表
老男孩Python高级全栈开发工程师-1 0001.开学典礼_ALEX简介 00:55:53 ☆ 0002.职业生涯_来培训的目的 01:12:29 ☆ 0003.课程目标 00:29: ...
- set的特性和基本用法——python3.6
特性 无序,不重复的数据组合,用{}表示,eg:{1,2,3,4,5,6} 用途 去重,把一个列表变成集合,就自动去重了 关系测试,测试两组数据之间的交集,差集,并集,对称差集,包含(子集和超集,相交 ...
- mongodb系统出错。 发生系统错误 1067。 进程意外终止。
MongoDB安装目录\data\将此文件夹下的mongod.lock删除 mongod.exe --config E:\ruanjian\MongoDB\mongod.cfg --remove mo ...
- HttpRunner自动化框架学习笔记
一.简单介绍 HttpRunner 是一款面向 HTTP(S) 协议的通用测试框架,只需编写维护一份 YAML/JSON 脚本,即可实现自动化测试.性能测试.线上监控.持续集成等多种测试需求. 支持p ...
- 【反省】qqxt第一场考试
我太蒟了 qwq 这是第一条 2:考试别水群,别乱fake,特别是要避免出现不顾考试时间每件事fake十分钟的情况 3:少想多写,虽然说写数据结构之前一定要先想好但是别墨迹. 4:保持对考试的敬畏,别 ...
- docker (centOS 7) 使用笔记1
1. docker配置 初次在安装完docker后,初始化配置 copy默认的docker.service后,重启服务,会在/etc/systemd/system/multi-user.target. ...
- 【bzoj3270】博物馆
同样是高斯消元,我写的版本就受到了歧视 我怎么又犯把 $j$ 打成 $i$ 这种 $sb$ 错误 题意 一张无向图,两个人分别从 $s_1$ 号点和 $s2$ 号点开始,每轮两人都会同时进行一次以下操 ...
- 【库存】NOI笔试习题集
https://wenku.baidu.com/view/2dc9d10854270722192e453610661ed9ad5155ba.html
- [AHOI2008]逆序对(dp)
小可可和小卡卡想到Y岛上旅游,但是他们不知道Y岛有多远.好在,他们找到一本古老的书,上面是这样说的: 下面是N个正整数,每个都在1~K之间.如果有两个数A和B,A在B左边且A大于B,我们就称这两个数为 ...
- linux下定时任务设置
原文http://www.blogjava.net/freeman1984/archive/2010/09/23/332715.html 觉这篇文章写的挺全的,把它拿过来存在博客里,方便以后查询. 为 ...