iOS

来源:互联网 发布:qq飞车优化设置 编辑:程序博客网 时间:2024/05/18 00:54

• iOS 网络层次结构 • 基于 iOS 提供 API 实现上传文件和断点续传的思路 
• 常用 iOS 第三方网路框架简介 - AFNetworking ( AFN ) - ASIHTTPRequest ( ASI ) 
• 另外一个常用框架 - SSZipArchive 
• ANF 使用演示 

iOS 网络编程层次结构示意图 



Cocoa 层 (NSURL,Bonjour,Game Kit,WebKit)  
     Core Foundation  层 ( 基于 C 的 CFNetwork 和 CFNetServices)  

OS 层 ( 基于 C 的 BSD socket) 
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 = [ AFJSONRequestOperationJSONRequestOperationWithRequest :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 框架是 不支持 ARC 的 
• 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

• 错误原因: 没有 GHUnit 框架 • 解决办法: 删除单元测试部分的代码引用 


删除单元测试代码引用示意图 


新建项目并导入 ASI 框架的步骤( 4 ) • 编译: 

 

85 个错误

瞬间凌乱有木有 ~~~ 
新建项目并导入 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 = [ NSURL URLWithString :string];  
// 2. 设定文件保存路径及缓存路径 
NSArray *documents = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory , NSUserDomainMask , YES ); 
NSString *downloadPath = [documents[ 0 ] stringByAppendingPathComponent :@"book.zip" ]; 
NSString *tempPath = [documents[ 0 ] stringByAppendingPathComponent :@"book.tmp" ]; 

ASI 下载文件请求定义部分代码 
// 3. 创建 ASIHTTPRequest ASIHTTPRequest *request = [ ASIHTTPRequestrequestWithURL :url];  // 4. 设置代理 --ASI 是通过代理回调的方式处理网络请求的[request setDelegate : self ];  
// 5. 设置下载路径 [request setDownloadDestinationPath :downloadPath];  
// 6. 设置缓存路径 [request setTemporaryFileDownloadPath :tempPath];  
// 7. 设置断点续传 [request setAllowResumeForFileDownloads : YES ];  
// 8. 设置下载进程代理 [request setDownloadProgressDelegate : self ];  
// 9. 启动异步请求 -- 用户想知道下载的实际进展情况 [request start ]; 

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 解压缩 [ SSZipArchive unzipFileAtPath :downloadPath toDestination:unzipPath]; 
// 3. 删除压缩文件 
[[ NSFileManager defaultManager ] removeItemAtPath :downloadPath error : 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 已停止更新 
不要视图完全吃透了再去使用,可以针对具体知识点去谷歌 + 度娘

0 0