•iOS网络层次结构•基于iOS提供API实现上传文件和断点续传的思路
•常用iOS第三方网路框架简介-AFNetworking(AFN)-ASIHTTPRequest(ASI)
•另外一个常用框架-SSZipArchive
•ANF使用演示
目标
•iOS网络层次结构•基于iOS提供API实现上传文件和断点续传的思路
•常用iOS第三方网路框架简介-AFNetworking(AFN)-ASIHTTPRequest(ASI)
•另外一个常用框架-SSZipArchive
•ANF使用演示
iOS网络编程层次结构示意图
Cocoa层(NSURL,Bonjour,Game Kit,WebKit)
Core Foundation层(基于C的CFNetwork和CFNetServices)
iOS 网络编程层次结构示意图
iOS 网络编程层次结构概述
• Cocoa 层 :是最上层的 基于 OC 的 API ,比如 URL 访问, NSStream , Bonjour , GameKit 等,这是大多数情况下我们常用的 API 。 Cocoa 层是基于 Core Foundation 实现的
• Core Foundation 层 : 基于 C 语言的框架 ,因为直接使用 socket 需 要更多的编程工作,所以苹果对 OS 层的 socket 进行简单的封装 以简化编程任务。该层提供了 CFNetwork 和 CFNetServices ,其 中 CFNetwork 又是基于 CFStream 和 CFSocket
• OS 层 :最底层的 BSD socket 提供了对网络编程最大程度的控制, 但是编程工作也是最多的。苹果建议我们使用 Core Foundation 及以上层的 API 进行编程。 BSD 是 UNIX 系统中通用的网络接口, 它不仅支持各种不同的网络类型,而且也是一种内部进程之间 的通信机制
不使用第三方框架如何实现 文件上传 ?
• 使用 NSURLConnection 无法通过 HTML 表单来上传 图片, 因此想要上传图片,必须实现 HTTP 请求 , 而不能像其他语言那样通过 HTML 表单的 POST 就 能上传
不使用第三方框架如何实现 断点续传 ?
• 要使用 NSURLConnection 实现断点续传
• 需要 自定义 URLRequest 的头部的 Range 属性 ,通知 URLConnection 只是 去获取部分网络内容
• Range 头域示例
• Range 头域可以请求实体的一个或者多个子范围。例如,
• 表示头 500 个字节: bytes=0-499
• 表示第二个 500 字节: bytes=500-999
• 表示最后 500 个字节: bytes=-500
• 表示 500 字节以后的范围: bytes=500-
• 第一个和最后一个字节: bytes=0-0,-1
• 同时指定几个范围: bytes=500-600,601-999
• 但是服务器可以忽略此请求头,如果 无条件 GET 包含 Range 请求头 ,响 应会以状态码 206 ( PartialContent )返回而不是以 200 ( OK )
为什么要选择第三方框架
• 第三方框架把复杂的网络底层操作 封装成友好的类和方法,并且加入 异常处理 等,从而可以:
- 高效的与服务端 API 进行数据交换 - 提高开发效率和稳定性
• 选择第三方框架的原则 1. 是否被广泛使用,有足够多得大牛验证过
2. 尽量保证能够看懂其中的所有代码 3. 可以学习编写其中部分方法, 但是不要去直接修改
常用的 iOS 网络开发框架
• AFNetworking ( AFN )
• ASIHTTPRequest ( ASI ) HTTP 终结者,非 ARC
备注: 2012 年 10 月 ASI 停止更新,但这并不意味着 ASI 的应用已经停止
AFN vs ASI • AFN :
- 官方推荐的使用方法: 为一系列相关的请求定义一个 HTTPClient ,共用一个 BaseURL 。每次请求把 URL 中除 BaseURL 的 Path 部分做为参数传给 HTTPClient 的静态方法,并注册一个 Block 用于回调
- 基于 NSURL ,性能和稳定性略差
- AFN 只封装了一些常用功能,满足基本需求,而直接忽略了很多扩展功能
- 针对 JSON 、 XML 、 PList 和 Image 四种数据结构封装了各自处理器,开发者可 以把处理器注册到操作队列中,直接在回调方法中获得格式化以后的数据
• ASI :
- 推荐使用方法:每一个请求都由构造方法初始化一个(共享)实例,通过这 个实例配置参数并发起请求。 ASI 最初使用 delegate 模式回调,在 iOS SDK 支持 Block 之后也提供了注册 Block 的实例方法(注: ASI 的 Block 不易使用)
- 基于 CFNetwork ,性能和稳定性略高
- ASI 的扩展功能非常丰富
- ASI 没有针对任何数据类型做特别封装,只是预留了各种接口和工具供开发者 自行扩展
AFN 和 ASI 的选择
• AFN 适合逻辑简单的应用 ,或者更适合开发资源尚不丰富的团队,因 为 AFN 的 易用性要比 ASI 好很多 ,而这样的应用(或团队)对底层网络 控件的定制化要求也非常低。
• ASI 更适合已经发展了一段时间的应用 ,或者开发资源相对丰富的团 队,因为往往这些团队(或他们的应用)已经积累了一定的经验,无 论是产品上还是技术上的。需求复杂度就是在这种时候高起来,而且 底层订制的需求也越来越多,此时 AFN 就很难满足需求,需要牺牲一 定的易用性 ,使用 ASI 作为网络底层控件。
AFNetworking ( AFN ) • 下载地址
https://github.com/AFNetworking/AFNetworking
• AFNetworking 官网地址: http://afnetworking.com
• 新建项目并导入 ANF 框架的步骤 • 演练
新建项目并导入 AFN 框架的步骤
• 1. 将框架程序拖拽进项目 • 2 . 添加 iOS 框架引用
- SystemConfiguration.framework
- MobileCoreServices.framework • 3. 修改 xxx-Prefix.pch 文件
#import #import
AFN--AFHTTPClient
• 1. 使用 baseURL 实例化
• 2. 建立 NSURLRequest
Ø 创建 GET 、 HEAD 、 PUT 、 DELETE 方法请求
² requestWithMethod:path:parameters:
Ø 创建 POST 方法请求
² multipartFormRequestWithMethod:path:parameters: constructingBodyWithBlock:
• 3. 检测网路连接状态 - setReachabilityStatusChangeBlock
AFHttpRequestOperation-- 对 NSURLConnection 的封装
• AFHttpRequestOperation HTTP 请求操作 Ø AFJSONRequestOperation 对 JSON 请求的封装 Ø AFXMLRequestOperation 对 XML 请求的封装 Ø AFPropertyListRequestOperation 对 Plist 请求的封装 Ø AFImageRequestOperation 对图像请求的封装
• 块代码操作 Ø setCompletionBlockWithSuccess 设置请求完成块代码
Ø setUploadProgressBlock 设置上传进度块代码 Ø setDownloadProgressBlock 设置下载进度块代码
• 下载操作需要设置 outputStream
Ø 针对请求的操作 pause (暂停) resume (继续)
检测网络连接状态
AFHTTPClient *client = [ AFHTTPClient clientWithBaseURL :[ NSURL URLWithString : @"http://www.baidu.com" ]];
[client setReachabilityStatusChangeBlock :^( AFNetworkReachabilityStatus status) { }];
加载 JSON & XML
AFJSONRequestOperation *op = [ AFJSONRequestOperation JSONRequestOperationWithRequest :request success :^( NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
NSLog ( @"%@" , JSON);
} failure :^( NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id
JSON) {
NSLog ( @"%@" , JSON);
}];
上传图像
NSURLRequest *request = [client multipartFormRequestWithMethod : @"POST" path : @"/~liufan9/ itcast/upload.php" parameters : nil constructingBodyWithBlock :^( id < AFMultipartFormData > formData) {
[formData appendPartWithFileData :imageData name : @"file" fileName : @"update.png" mimeType : @"image/png" ];
}];
// 定义操作 AFHTTPRequestOperation *operation = [[ AFHTTPRequestOperation
alloc ] initWithRequest :request]; // 设置上传 // 设置下载进度
演练( 6 ) -- 断点续传 • 设置操作的 输出流 (在网络中的数据是流的方式传输)
• [operation setOutputStream :[ NSOutputStream outputStreamToFileAtPath :downloadPath append : YES ]];
解压缩 -- 另一个第三方框架 SSZipArchive
下载地址: https://github.com/samsoffes/ssziparchive
注意: 需要引入 libz.dylib 框架
// Unzipping
NSString * zipPath = @"path_to_your_zip_file" ;
NSString * destinationPath = @"path_to_the_folder_where_you_want_it_unzipped" ; [SSZipArchive unzipFileAtPath : zipPath toDestination : destinationPath];
// Zipping
NSString * zippedPath = @"path_where_you_want_the_file_created" ; NSArray * inputPaths = [NSArray arrayWithObjects :
[[NSBundle mainBundle] pathForResource : @"photo1" ofType : @"jpg" ], [[NSBundle mainBundle] pathForResource : @"photo2" ofType : @"jpg" ] nil ];
[SSZipArchive createZipFileAtPath : zippedPath withFilesAtPaths : inputPaths];
ASIHTTPRequest ( ASI )
http://github.com/pokeb/asi-http-request/tarball/master
• 新建项目并导入 ASI 框架的步骤 • 演练:
- 从服务器下载文件并解压缩
使用 ASI 的两点注意事项
• ASI 框架是 基于i OS5.0 的,如果选择i OS6.0 会有一些苹果官方不再维护 的方法
新建项目并导入 ASI 框架的步骤( 1 )
• 新建项目, 不选择 ARC 支持 • 将 Deployment Target 修改为 5.0
• 将 ASI 解压缩包中的以下两个文件夹拖入项目
- Classes - External
新建项目并导入 ASI 框架的步骤( 2 )
• 编译出现错误: ASIWebPageRequest.m:13:9: 'libxml/HTMLparser.h' file not found
• 错误原因: - 无法正确找到 libxml/HTMLparser.h
• 解决方法: - 在头文件搜索目录中添加: ${SDK_DIR}/usr/include/libxml2
添加搜索路径示意图
新建项目并导入 ASI 框架的步骤( 3 ) • 编译出现错误:
ASITestCase.h:12:9: 'GHUnitIOS/GHUnit.h' file not found
新建项目并导入 ASI 框架的步骤( 4 )
• 解决方法:添加以下 iOS 框架引用 - CFNetwork.framework
- SystemConfiguration.framework - MobileCoreServices.framework - libz.dylib
- libxml2.dylib
• 怎么知道需要这些框架?
编译通过
ASI 断点续传实现思路回顾
• 目标:使用断点续传的方式下载 zip 文件并解压缩 • 思路:
1. 指定下载文件地址 2. 设定文件保存路径及缓存路径 3. 创建 ASIHTTPRequest
4. 设置 代理 --ASI 是通过代理回调的方式处理网络请求的 5. 设置下载路径 6. 设置缓存路径 7. 设置断点续传 8. 设置下载进程 代理 -- 用户想知道下载的实际进展情况 9. 启动异步请求
ASI 下载文件的准备工作 -- 源和目标
// 1.指定下载文件地址
NSString*string =@"http://localhost/~liufan9/itcast/download/iTunesConnect_DeveloperGuide_CN.zip";
NSURL*url = [NSURLURLWithString:string];
// 2.设定文件保存路径及缓存路径
NSArray*documents =NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString*downloadPath = [documents[0]stringByAppendingPathComponent:@"book.zip"];
NSString*tempPath = [documents[0]stringByAppendingPathComponent:@"book.tmp"];
ASI下载文件请求定义部分代码
// 3.创建ASIHTTPRequestASIHTTPRequest*request = [ASIHTTPRequestrequestWithURL:url]; // 4.设置代理--ASI是通过代理回调的方式处理网络请求的[requestsetDelegate:self];
// 5.设置下载路径[requestsetDownloadDestinationPath:downloadPath];
// 6.设置缓存路径[requestsetTemporaryFileDownloadPath:tempPath];
// 7.设置断点续传[requestsetAllowResumeForFileDownloads:YES];
// 8.设置下载进程代理[requestsetDownloadProgressDelegate:self];
// 9.启动异步请求--用户想知道下载的实际进展情况[requeststart];
NSURLConnectionDataDelegate的代理方法回顾
//服务器开始返回数据-(void)connection:didReceiveResponse: //收到服务器返回的数据,本方法会被调用多次- (void)connection:didReceiveData:
//数据接收完毕-(void)connectionDidFinishLoading:
//网络连接错误- (void)connection:didFailWithError: //发送数据给服务器,POST请求使用此方法
- (void)connection:didSendBodyData:totalBytesWritten: totalBytesExpectedToWrite:
ASIRequest代理方法
//请求开始
- (void)requestStarted:(ASIHTTPRequest*)request
//请求接收到响应的头部,包括文件大小信息
- (void)request:(ASIHTTPRequest*)request didReceiveResponseHeaders: (NSDictionary*)responseHeaders
//请求完成- (void)requestFinished:(ASIHTTPRequest*)request
//请求失败- (void)requestFailed:(ASIHTTPRequest*)request对比结果:1.ASIRequest不需要处理中间数据2.但是请求开始拆分成了两部分
实现代理方法之前需要先遵从代理协议
1.ASIHTTPRequestDelegate 2.ASIProgressDelegate
ASIRequest代理方法实现(1)
•给四个代理方法添加NSLog,看看都在干什么•目的:运行根据Log结果写思路•请求头部可以看到文件长度,思路如下:
// 2.发现其中有一个"Content-Length" = 6105204;//貌似是和文件下载进度有关的工作可以在这里进行//暂时先放一下
•请求完成://需求:
// 1.知道文件保存路径// 2.解压缩文件// 3.删除压缩文件
下一目标解压缩文件
运行看看文件来了吗?
解压缩--另一个第三方框架SSZipArchive下载地址:https://github.com/samsoffes/ssziparchive
注意:需要引入libz.dylib框架
// Unzipping
NSString*zipPath=@"path_to_your_zip_file";
NSString*destinationPath=@"path_to_the_folder_where_you_want_it_unzipped"; [SSZipArchive unzipFileAtPath:zipPath toDestination:destinationPath];
// Zipping
NSString*zippedPath=@"path_where_you_want_the_file_created"; NSArray*inputPaths=[NSArray arrayWithObjects:
[[NSBundle mainBundle] pathForResource:@"photo1"ofType:@"jpg"], [[NSBundle mainBundle] pathForResource:@"photo2"ofType:@"jpg"]nil];
[SSZipArchive createZipFileAtPath:zippedPath withFilesAtPaths:inputPaths];
请求完成部分代码实现
NSLog(@"请求完成");
//需求:// 1.知道文件保存路径(运行,发现文件已经下载完成了)// 2.解压缩文件(导入SSZipArchive框架)//根据SSZipArchive框架用法写思路// 2.1设置压缩文件路径
NSArray*documents =NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString*downloadPath = [documents[0]stringByAppendingPathComponent:@"book.zip"];
// 2.2设置解压缩文件路径,保存在当前路径NSString*unzipPath = documents[0];
// 2.3解压缩[SSZipArchiveunzipFileAtPath:downloadPathtoDestination:unzipPath];
// 3.删除压缩文件
[[NSFileManagerdefaultManager]removeItemAtPath:downloadPatherror:nil];
下载进度跟踪--ASIProgressDelegate下一目标
ASIProgressDelegate--setProgress
#pragma mark -下载进度代理方法- (void)setProgress:(float)newProgress {
//通过Log发现传入的是一个百分比的数组//现在需要一个文件大小,并提示用户文件的大小
NSLog(@"%f", newProgress); }
ASIRequest响应头部的代码实现
1. ASIRequest响应头部的代码实现
// 1. NSLOG看看头部是什么内容NSLog(@"%@", responseHeaders);
// 2.发现其中有一个"Content-Length" = 6105204;//貌似是和文件下载进度有关的工作可以在这里进行//将文件大小转换成M为单位 字节-K-M_fileLength= request.contentLength/1024.0/1024.0;NSLog(@"%.2fM",_fileLength);
2. setProgress方法NSLog(@"%.2f", newProgress *_fileLength);
ASI框架小结
• ASI框架是不支持ARC的
• ASI框架是基于iOS5.0的
• 使用前的准备工作有点繁琐
• 目前有不少的公司在使用ASI框架,不过大多新的项目已经转用AFN框 架
• 2012年10月ASI停止更新,但这并不意味着ASI的应用已经停止
• 学习也是需求驱动的,知道了ASI框架的基础用法后,今后工作中如 果需要,可以针对具体知识点去谷歌+度娘
关于第三方框架的小结
•第三方框架把复杂的网络底层操作封装成友好的类和方法,并且加入异常处 理等,从而可以:
-高效的与服务端API进行数据交换
-提高开发效率和稳定性•选择第三方框架的原则
1.尽量保证能够看懂其中的所有代码2.是否被广泛使用3.可以学习编写其中部分方法,但是不要去直接修改
常用的iOS网络开发框架-AFN适合逻辑简单的应用,基于NSURL
-ASI更适合已经发展了一段时间的应用,基于CFNetwork已停止更新
不要视图完全吃透了再去使用,可以针对具体知识点去谷歌+度娘