•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)
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 = [
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
)
•
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 = [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已停止更新
不要视图完全吃透了再去使用,可以针对具体知识点去谷歌+度娘