您的位置:首页 > 理论基础 > 计算机网络

iOS网络请求第三方框架:MKNetworkKit介绍及简单使用

2014-09-21 19:46 781 查看
一.介绍

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 内置了缩略图缓存。只要覆盖几个方法,
15c6f
就可以设置内存中最大能缓存的图片数量,以及缓存要保存到目录。当然,你也可以不覆盖这些方法。

(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

 

 

           

 

 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  网络 框架 iphone