一、网络请求

在网络开发中。须要了解一些经常使用的请求方法:
  • 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:@"协议://主机地址/路径?參数&參数"];
解释例如以下:
  • 协议:不同的协议,代表着不同的资源查找方式、资源传输方式,比方经常使用的httpftp
  • 主机地址:存放资源的主机的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的更多相关文章

  1. NodeJS学习笔记 (12)网络地址解析-url(ok)

    模块概述 nodejs中,提供了url这个非常实用的模块,用来做URL的解析.在做node服务端的开发时会经常用到.使用很简单,总共只有3个方法. 正式讲解前,各位同学先把下面这个图记在心上(来自no ...

  2. iOS学习笔记-精华整理

    iOS学习笔记总结整理 一.内存管理情况 1- autorelease,当用户的代码在持续运行时,自动释放池是不会被销毁的,这段时间内用户可以安全地使用自动释放的对象.当用户的代码运行告一段 落,开始 ...

  3. iOS学习笔记22-推送通知

    一.推送通知 推送通知就是向用户推送一条信息来通知用户某件事件,可以在应用退到后台后,或者关闭后,能够通过推送一条消息通知用户某件事情,比如版本更新等等. 推送通知的常用应用场景: 一些任务管理APP ...

  4. iOS学习笔记13-网络(二)NSURLSession

    在2013年WWDC上苹果揭开了NSURLSession的面纱,将它作为NSURLConnection的继任者.现在使用最广泛的第三方网络框架:AFNetworking.SDWebImage等等都使用 ...

  5. IOS学习笔记25—HTTP操作之ASIHTTPRequest

    IOS学习笔记25—HTTP操作之ASIHTTPRequest 分类: iOS2012-08-12 10:04 7734人阅读 评论(3) 收藏 举报 iosios5网络wrapper框架新浪微博 A ...

  6. iOS学习笔记总结整理

    来源:http://mobile.51cto.com/iphone-386851_all.htm 学习IOS开发这对于一个初学者来说,是一件非常挠头的事情.其实学习IOS开发无外乎平时的积累与总结.下 ...

  7. IOS学习笔记07---C语言函数-printf函数

    IOS学习笔记07---C语言函数-printf函数 0 7.C语言5-printf函数 ------------------------- ----------------------------- ...

  8. IOS学习笔记06---C语言函数

    IOS学习笔记06---C语言函数 --------------------------------------------  qq交流群:创梦技术交流群:251572072              ...

  9. IOS学习笔记02---语言发展概述,计算机语言简介.

    IOS学习笔记02---语言发展概述,计算机语言简介. ------------------------------------------------------------------------ ...

随机推荐

  1. linux随笔四

    1.ps -ef     : -e   显示系统上运行的所有进程,-f 显示一些有用的信息列 UID:负责启动进程的用户 PID:进程的ID PPID:父进程的PID(某个进程由另一个进程启动) C: ...

  2. sql server 学习分享

    http://www.cnblogs.com/liu-chao-feng/p/6144872.html

  3. 缓存淘汰算法之LFU

    1. LFU类 1.1. LFU 1.1.1. 原理 LFU(Least Frequently Used)算法根据数据的历史访问频率来淘汰数据,其核心思想是“如果数据过去被访问多次,那么将来被访问的频 ...

  4. Educational Codeforces Round 20 D. Magazine Ad

    The main city magazine offers its readers an opportunity to publish their ads. The format of the ad ...

  5. Oracle的表空间、数据文件、用户

          每一个Oracle数据库都是由三种类型的文件组成:数据文件(Data File).日志文件(Log File)和控制文件(Control File).数据库的文件为数据库信息提供真正的物理 ...

  6. STL之map容器的详解

    一.关于map的介绍 map是STL的 一个容器,和set一样,map也是一种关联式容器.它提供一对一(其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可能称为该关键 字的值)的数据 ...

  7. 九度oj 题目1348:数组中的逆序对

    题目描述: 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数. 输入: 每个测试案例包括两行: 第一行包含一个整数n,表示数组 ...

  8. scikit-learn使用方法

    1.支持向量机 #_*_ coding:utf-8 _*_ from sklearn import datasets from sklearn import svm #装载内部测试数据集 digits ...

  9. [SCOI2008]配对 (贪心,动态规划)

    题目链接 Solution 很妙的DP,很妙的贪心. 首先考虑,如果说没有那个相同的不能配对的情况; 那么我们肯定是直接排两遍序,然后一一对应即可. 但是是有限制的,同时我们可得几个条件供贪心: 每个 ...

  10. spring-boot项目热部署以及spring-devtools导致同类不能转换

    <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring- ...