一.介绍
MKNetworkKit 综合了ASIHTTPRequest 和AFNetworking两个类库的特点,并且有一些新的特点比如:完全支持ARC,基于block并且简单易用.
二.特性
1.超轻量级
区别于其他第三方框架提供众多的类供使用,MKNetworkKit类库中只有两个类(MKNetworkOperation和MKNetworkEngine)和少量类目,而且内部封装的方法简单易用. 我们所需要了解的就是暴露在两个类MKNetworkOperation和 MKNetworkEngine中的方法。MKNetworkOperation就好比ASIHttpRequest类。它是一个NSOperation子类,封装了你的request和response类。对于每个网络操作,你需要创建一个MKNetworkOperation。
MKNetworkEngine是一个伪单例类,管理程序中的网络队列。它是伪单例的,也就是说,对于简单请求,你可以直接用MKNetworkEngine中的方法。要进行深度的定制,你应该进行子类化。每个MKNetworkEngine子类有它自己的Reachability对象,用于通知它来自服务器的reachability通知。对于不同的REST服务器,你可以考虑创建单独的MKNetworkEngine子类。
它是伪单例,它的子类的每个请求都共用唯一的一个队列。你可以在应用程序委托中retain这个MKNetworkEngine,就像CoreData的managedObjectContext 类一样。在使用MKNetworkKit时,创建一个MKNetworkEngine子类将你的网络请求进行逻辑上的分组。例如,将所有关于Yahoo的方法放在一个类,所有Facebook有关的方法放进另一个类。
2.整个应用共享单一队列
手机应用对网络的依赖性越来越严重,这就需要开发者着重注意优化网络并发连接数.举个简单的例子:
假如你正在上传一系列的图片到服务器,这就可能需要多个并发的http请求,但是大多数的移动网络(3G)不允许一个给定的IP地址超过两个的并发的http请求,也就是说,当你的设备处在3G网络下,你不能同时打开超过两个的并发HTTP请求,EDGE网络就更差了,甚至只能打开一个链接.如果是WIFI环境的话,这个限制会宽松一些,最多允许6个并发的HTTP请求.问题是,我们的设备不可能一直能连接到WIFI. 所以开发者应该为受限制的网络环境考虑,当被限制只能上传两张照片时,问题来了,并不是说速度慢的问题,而是当用户在上传的同时打开了新的页面,创建了另外一个(也就是第三个)HTTP请求,而这个页面在加载图片的缩略图,用户当前想要看到的正是这个页面时可能出现的请求超时问题.还记得前面说的在3G网络下不能创建超过两个的并发http请求吗?当你的后台已经并发了两个http请求(上传图片),而你又没有通过APP控制正确的队列大小时,第三个http请求只能等待,所以会出现请求超时的情况.正确的做法是:把缩略图的加载排好优先级,优化缩略图加载线程,或者等待上传完成后再加载缩略图.这就要求你的APP有一个全局的队列.MKNetworkKit提供了单一的共享队列,可以保证你的APP的每一个队列实例使用单一的共享队列(MKNetworkKit本身并不是单例,但是他提供的共享队列是一个单列)
3.正确显示网络状态指示
由于提供单例的共享队列,所以使用MKNetworkKit可以自动的显示网络状态.具体来说,在共享队列中有一个线程通过KVO方式随时观察OperationCount属性,因此对于开发者来说不需要考虑网络状态的显示
if(object== _sharedNetworkQueue&&[keyPath isEqualToString:@"operationCount"])
{
[UIApplication sharedApplication].networkActivityIndicatorVisible= ([_sharedNetworkQueue.operations count]>0);
}
4.其他特性:
(1)自动改变队列大小:
因为绝大部分移动网络不允许2个以上的并发连接,因此你的队列大小在3G网络下应该设置为2.MKNetworkKit会自动的处理好这个.当网络处于3G/EDGE/GPRS时,它会将并发数调整到2,当网络为WIFI网络时,自动调整到6.
(2) Auto caching 自动缓存
MKNetworkKit能够自动缓存所有的GET请求,当再次发起同样的请求时, MKNetworkKit随机就能调用可用的response缓存传递给handler进行处理.当然,它同时也像服务器发出请求,一旦获得服务器数据,handler被再次要求处理新获得的数据,开发者不用手动缓存,只需要使用
[[MKNetworkEngine sharedEngine] useCache];
(3)Operation freezing 操作冻结
冻结操作是MKNetworkKit中最有趣的操作了,当一个操作被冻结时,为了防止网络链接丢失,操作会被自动序列化并且在设备联网之后自动执行. 类似于微博客户端的草稿箱功能. 当你发送一条微博时,如果把这个网络操作标记为冻结,MKNetworkKit会自动的处理冻结和解冻操作,那么这条微博你可以不用写一行代码就会被自动稍后发送,类似的,你可以使用在:标记一条微博为喜欢或者从google reader客户端分享一篇文章或者添加一个链接到instpaper等场景中.
(4)Performsexactly one operation for similar requests对类似的请求只执行一个一个操作
当你加载缩略图(针对twitter stream)时,你最终得为每个实际的图片创建一个新的请求。但实际上你所进行的多个请求都是同一个URL。MKNetworkKit 对于队列中的每个 GET 请求都只会执行一次。而且不会缓存POST请求.
(5) Image Cache 图片缓存
MKNetworkKit 内置了缩略图缓存。只要覆盖几个方法,就可以设置内存中最大能缓存的图片数量,以及缓存要保存到目录。当然,你也可以不覆盖这些方法。
(6)Performance 性能
也就是速度,因为MKNetworkKit的缓存是内置的,就像NSCache一样工作,此外,当出现内存警告时,内存缓存会写入到缓存目录
(7)全面支持ARC
二.使用前提
1. 首先需要下载类库: https://github.com/MugunthKumar/MKNetworkKit (下载原作者的Demo,就可以得到类库)
提示:从github上下载下来的作者的源码包括很多内容:
在运行Demo之前需要先运行MKNetworkKit.xcworkspace
2. 简单用法:
(1)新建一个iOS工程,在工程中导入MKNetworkKit包;
(2)在项目中添加以下框架:SystemConfiguration.framework,CFNetwork.framework,Security.framework和ImageIO.framework,如下图:
(3)在新建工程的.pch文件中导入”MKNetworkKit.h”
(4)注意:iOS工程下使用MKNetworkKit,需要删除NSAlert+MKNetworkKitAdditions.h文件,当然,如果是Mac工程下需要删除UIAlert+MKNetworkKitAdditions.h文件.
(5)注意我们写好的方法应该按照以下顺序执行
1. 准备好url和请求参数
2. 创建一个请求的MKNetworkOperation对象.
3. 设置方法参数
4. 添加完成和错误处理方法,(完成方法就是你处理你响应到相应的model类的地方)
5. 可选的,还有请求操作的进度指示。(或者在viewController里面处理)
6. 如果你的操作时下载文件,那么设置一个下载的流(通常是一个文件)给他,这也是可选的
7. 当请求操作完成时,处理结果并且调用block方法来向调用方法返回数据。
(6) MKNetworkOperation中的便捷方法
MKNetworkOperation 提供了一些如下便捷方法来方便你格式化你的响应数据
responseData
responseString
responseJSON (Onlyon iOS 5)
responseImage
responseXML
error
从网络请求获取响应很方便,当返回格式错误时,这些方法返回nil,比如试图从响应为html中获取image会返回nil,唯一可以确保返回正确结果的方法时responseData,如果你确定返回类型,可以用其他方法。
三.简单用法
新建一个工程,在viewController中操作
1. GET请求
MKNetworkEngine中包含一下几个常用的初始化方法:
而MKNetworkOperation的初始化,基于已经初始化的MKNetworkEngine对象,
示例一:
最简单的GET请求:直接使用url地址字符串,请求淘宝网页.
注意:使用的是字符串而不是url地址,这里需要手动添加http://(如果使用hostname的话不需要添加http://, MKNetworkKit会自动帮我们补全)
MKNetworkEngine *engine = [[MKNetworkEnginealloc]init]; //初始化操作队列
MKNetworkOperation *op = [engine operationWithURLString:@"http://www.taobao.com"]; //初始化需要进行的操作
[op onCompletion:^(MKNetworkOperation *completedOperation) { //操作完成之后回调的block代码块,这里是让网页显示在当前屏幕上
UIWebView *webView = [[UIWebView alloc]initWithFrame:CGRectMake(0,20, 320, 460)];
[webView loadData:[completedOperation responseData]MIMEType:niltextEncodingName:nilbaseURL:nil];
webView.scalesPageToFit =YES;//使web页面适应手机屏幕显示,内容变小
[self.viewaddSubview:webView];
} onError:^(NSError *error) {
NSLog(@"error:%@",error);
}];
//将操作添加进队列
[engine enqueueOperation:op];
结果就像这样:
示例二:使用hostname
/*
1.MKNetworkEngine的初始化方法需要主机名和自定义的header(如果有)
2.这里主机名不需要手动添加"http://",MKNetworkKit会自动帮我们添加.
3.自定义的头是可选的而且可以为nil
4.如果你正在编写自己的REST服务器(不是现在的情况)你可能需要考虑添加客户端版本以及其他类似客户端标识的元数据。
*/
MKNetworkEngine *engine = [[MKNetworkEnginealloc]initWithHostName:@"www.taobao.com"customHeaderFields:nil];
//Path指的是相对路径,这里链接到淘宝某一个页面,只是使用主机名而Path为nil的话,会跳转到淘宝登陆界面,而不是首页,这点和使用url访问有区别
MKNetworkOperation *op = [engine operationWithPath:@"/market/3c/home.php?spm=1.7274553.1997517385.d8.A45hkn"];
//MKNetworkOperation *op = [engine operationWithPath:nil params:nilhttpMethod:@"GET"];//链接不到淘宝主页
[op onCompletion:^(MKNetworkOperation *completedOperation) {
UIWebView *webView = [[UIWebView alloc]initWithFrame:CGRectMake(0,20, 320, 460)];
[webView loadData:[completedOperation responseData]MIMEType:niltextEncodingName:nilbaseURL:nil];
webView.scalesPageToFit =YES;//使web页面适应手机屏幕显示,内容变小
[self.viewaddSubview:webView];
} onError:^(NSError *error) {
NSLog(@"error:%@",error);
}];
[engine enqueueOperation:op];
结果就像这样:
Path不为nil(左)和Path为ni(右,没有具体的内容,只有网站框架)
示例三:获取网络json数据
//获取网络json数据(get)请求
MKNetworkEngine *engine = [[MKNetworkEnginealloc]initWithHostName:@"api.douban.com"customHeaderFields:nil];
//MKNetworkOperation *op = [engineoperationWithPath:@"v2/movie/us_box"params:nilhttpMethod:@"GET"];
MKNetworkOperation *op = [engine operationWithPath:@"v2/movie/us_box"params:nil httpMethod:@"GET" ssl:NO];
/*
Secure Sockets Layer,简称 SSL)可使通过网络连接的两个应用程序相互对各自的标识进行身份验证,同时还可以对应用程序间的数据交换进行加密,以此来提供安全的连接。身份验证允许服务器和(可选)客户端对网络连接另一端的应用程序的标识进行验证。加密可以使通过网络传输的数据只被预定接收方识别。
*/
[op onCompletion:^(MKNetworkOperation *completedOperation) {
NSLog(@"responseData:%@",[opresponseJSON]); //MKNetworkOperation封装了一个解析json数据的方法responseJson,方法内部使用系统自带额json数据解析工具对获取的数据进行解析之后返回回来
} onError:^(NSError *error) {
NSLog(@"error:%@",error);
}];
[engine enqueueOperation:op];
注意:
对于以下两个方法,区别在于apiPath,
1. MKNetworkEngine *engine =[[MKNetworkEngine alloc]initWithHostName:<#(NSString *)#>apiPath:<#(NSString *)#> customHeaderFields:<#(NSDictionary *)#>];
2. MKNetworkEngine *engine =[[MKNetworkEngine alloc]initWithHostName:<#(NSString *)#>customHeaderFields:<#(NSDictionary *)#>];
apipath参数是可选的,apipath是每一个Path操作请求的前缀:如果你的服务器的API的位置不是从根路径开始的,可以使用这种方法(/)
参考资料: http://stackoverflow.com/questions/21530218/mknetworkkit-host-name-and-apipath-parameters
示例四:下载网络图片文件并保存在本地
//初始化图片视图
UIImageView *imgView = [[UIImageView alloc]initWithFrame:CGRectMake(50,100,220, 180)];
[self.viewaddSubview:imgView];
MKNetworkEngine *engine = [[MKNetworkEnginealloc]initWithHostName:@"img4.duitang.com"customHeaderFields:nil];
MKNetworkOperation *op = [engine operationWithPath:@"uploads/item/201210/06/20121006005958_mGESG.jpeg"params:nil httpMethod:@"GET" ssl:NO];
//获取当前文件额沙盒目录,把图片下载到当前目录并保存为beauty.jpeg
NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/beauty.jpeg"];
NSLog(@"path = %@",path);
[op addDownloadStream:[NSOutputStream outputStreamToFileAtPath:path append:YES]];//从网络下载文件的方法,MKNetworkOperation内部封装了一个responseImae的方法
[op onCompletion:^(MKNetworkOperation *completedOperation) {
imgView.image = [UIImageimageWithContentsOfFile:path];
//imgView.image = [op1 responseImage]; //直接使用MKNetworkOperation内部封装了一个responseImae的方法
} onError:^(NSError *error) {
NSLog(@"%@",error);
}];
//添加至执行队列-------先执行图片下载
[engine enqueueOperation:op];
下载文件到本地目录 (缓存)
使用MKNetworkKit 从服务器下载文件并保存到 iPhone 的本地目录非常简单.只需要设置MKNetworkOperation的 outputStream 。
[operation setDownloadStream:[NSOutputStream outputStreamToFileAtPath:@"/Users/mugunth/Desktop/DownloadedFile.pdf" append:YES]]; |
你可以设置多个outputStream 到一个 operation,将同一文件保存到几个地方(例如其中一个是你的缓存目录,另一个用做你的工作目录)。
A.缓存图片的缩略图
对于下载图片,你可能需要提供一个绝对 URL地址而不是一个路径。
MKNetworkEngine 的operationWithURLString:params:httpMethod:方法根据绝对 URL地址来创建网络线程。
MKNetworkEngine 相当聪明。它会将同一个 URL 的多次 GET 请求合并成一个,当 operation 完成时它会通知所有的块。这显著提升了抓取图片 URL 以渲染缩略图的速度.
子类化 MKNetworkEngine然后覆盖图片的缓存目录及缓存的大小。如果你不想定制这二者,你可以直接调用 MKNetworkEngine中的方法来下载图片。这是原作者极力推荐的。
B.缓存operation
MKNetworkKit 默认会缓存所有请求。你所需要的仅仅是在你自己的 engine 中打开它。当执行一个 GET 请求时,如果上次的 response 已缓存,相应的 completion 块将用缓存的response 进行调用(瞬间)。要想知道 response 是否缓存,可以调用 isCachedResponse 方法,如下所示:
[op onCompletion:^(MKNetworkOperation *completedOperation) {
imgView.image = [UIImageimageWithContentsOfFile:path];
// imgView.image = [opresponseImage]; //直接使用MKNetworkOperation内部封装了一个responseImae的方法
if ([completedOperation isCachedResponse]) {
NSLog(@"Data from cache");
}else
{
NSLog(@"Data from server");
}
NSLog(@"%@",[completedOperation responseString]);
} onError:^(NSError *error) {
NSLog(@"%@",error);
}];
2. POST请求:使用POST向服务器传输数据
//post请求
engine = [[MKNetworkEnginealloc]initWithHostName:@"192.168.2.176:3000"customHeaderFields:nil];
NSMutableDictionary *dic = [[NSMutableDictionaryalloc]init];
[dic setValue:@"admin" forKey:@"username"];
[dic setValue:@"123" forKey:@"password"];
op = [engine operationWithPath:@"/login" params:dic httpMethod:@"POST"];
[op onCompletion:^(MKNetworkOperation *completedOperation) {
NSLog(@"[operationresponseData] ->>%@",[completedOperationresponseString]);
} onError:^(NSError *error) {
NSLog(@"MKNetworkrequest error:%@",[errorlocalizedDescription]);
}];
[engine enqueueOperation:op];
3.冻结operation
MKNetworkKit的一个最有趣的特性是它内置的冻结 operation 特性。你只需要设置 operation 的 freeesable 属性就可以。几乎什么也不用做!
[opsetFreezable:YES];
冻结是指 operation 在网络被断开时自动序列化并在网络恢复后自动执行。例如当你离线时也能够进行收藏tweet 的操作,然后在你再次上线时 operation 自动恢复执行。
在应用程序进入后台时,冻结的operation 也会被持久化到磁盘。然后在应用程序回到前台后自动恢复执行。
参考文献:
1.此框架的作者MugunthKumar提供的官方说明文档(全英):
http://blog.mugunthkumar.com/products/ios-framework-introducing-mknetworkkit/
2.比较好的译文
http://www.cocoachina.com/bbs/read.php?tid=184145
http://blog.csdn.net/kmyhy/article/details/12276287
3.原作者示例代码的下载地址
https://github.com/MugunthKumar/MKNetworkKit
4.有关使用的参考文献
http://blog.csdn.net/mobailwang/article/details/25056959
http://blog.csdn.net/u012743459/article/details/39377275