一、MKNetworkKit介绍
MKNetworkKit是一个用OC语言实现的方便、简洁、强大的网络框架,基于block和ARC。MKNetworkKit集合了ASIHTTPRequest强大的功能和AFNetworking简洁的特点,并且在此基础上又增加了一些新的功能,用最少最简洁的代码实现网络请求。下面将会对这些功能做详细的说明。
二、MKNetworkKit特征
1、超轻量级框架
整个框架只有2个类,和一个共享的网络请求队列,使用起来方便简单。
2、自动显示网络状态指示
许多第三方框架都通过一个“网络连接数增加/减少”的方法回调来显示网络状态,而MKNetworkKit由于使用了单例的共享队列,在共享队列中有一个线程通过KVO方式会随时观察operationCount属性,能自动显示网络状态。这为开发者提供了很大的便利。
3、自动改变请求队列大小
当网络出于3G/EDGE/GPRS 时,MKNetworkKit会将并发数调整到 2。当网络处于 Wifi 网络时,则自动调整到 6。当通过 3G 网络中从远程服务器加载缩略图时,这种调整能带来极大的好处。
4、自动缓存
MKNetworkKit能自动缓存程序中所有的GET请求。当再次发起同样的请求时,MKNetworkKit随即就能调用response缓存(如果可用的话)传递给handler进行处理。当然,它同时也向服务器发出请求。一旦获得服务器数据,handler被再次要求处理新获取的数据。也就是说,不需要手动缓存。只需要使用:
[[MKNetworkEnginesharedEngine] useCache];
当然,亦可以覆盖这个方法(子类化),定制自己的缓存路径和缓存占用的内存开销。
5、冻结网络操作
MKNetworkKit能够“冻结”网络操作。在一个网络操作被“冻结”的情况下,一旦网络连断开,它们将自动序列化并在设备再次连线时自动被提交一次。
6、类似的请求只执行一次操作
当你加载缩略图时,你最终得为每个实际的图片创建一个新的请求。实际上你所进行的多个请求都是同一个URL。MKNetworkKit对于队列中的每个GET请求都只会执行一次。
7、图片缓存
MKNetworkKit内置了缩略图缓存。只要覆盖几个方法,就可以设置内存中最大能缓存的图片数量,以及缓存要保存到目录。
8、性能
即速度。MKNetworkKit缓存是内置的,就如NSCache,当发现有内存警告,缓存到内存中的数据将被写入缓存目录。
9、完全支持ARC
三、MKNetworkKit用法
MKNetworkKit下载地址
https://github.com/MugunthKumar/MKNetworkKit
1、github下载了该框架后,如果想要运行其demo,需要做以下操作,这里以IOS-demo为例进行说明:
首先选中项目里的iOS-Demo文件夹并打开,然后将项目里的MKNetworkKit文件夹拖拽到打开的demo里(这即是给项目添加第三方框架),之后再将MKNetworkKit.h头文件包含到pch文件中,此时还需要注意的是,要把程序中要用到的那张图片也添加进demo里,当然也要使用arc,这是再编译运行就ok了。
2、如果是想在自己的代码里添加MKNetworkKit框架,则需要做以下操作:
1)、将MKNetworkKit目录拖到项目中
2)、选中Bulid Phases下的Link Binary With Libraries,点击+号添加下列库文件: CFNetwork.Framework, SystemConfiguration.framework,Security.framework and ImageIO.Framework.
3)、将 MKNetworkKit.h 头文件包含到 PCH 文件中,如下面代码所示
4)、对于iOS,删除 NSAlert+MKNetworkKitAdditions.h(不要与MKNetworkKit提示冲突,MKNetworkKit会自动进行显示隐藏)
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import "MKNetworkKit.h"
#import "AppDelegate.h"
#endif
3、MKNetworkKit的类
1)MKNetworkOperation
2)MKNetworkEngine
3)一些工具类 (Apple 的 Reachability) 以及类别
4、源码实例分析
该实例是通过创建一个YahooEngine来获取雅虎财经的货币交换率。
步骤1、创建一个YahooEngine类继承自MKNetworkEngine。MKNetworkEngine的初始化方法需要主机名和自定义的header(如果有)。自定义的头是可选的而且可以为nil。
//下面这段代码是是为了演示此功能特性,需要注意的是,雅虎是不需要发送x-client-identifider在header里面的
NSMutableDictionary *headerFields = [NSMutableDictionarydictionary];
[headerFields setValue:@"iOS"forKey:@"x-client-identifier"];
self.engine = [[YahooEngine alloc]initWithHostName:@"download.finance.yahoo.com"customHeaderFields:headerFields];
//下面这段代码是该实例中对MKNetworkEngine的初始化
self.yahooEngine = [[YahooEngine alloc] initWithHostName:@"download.finance.yahoo.com"];
[self.yahooEngine useCache];
[注]:如果代码较简单,那可以在自己的AppDelegate中初始化一个类似先前的yahooEngine的Engine,如果代码比较复杂,也可以子类化一个testsEngine来对其进行自定义。
步骤2、设计 Engine 类 (分离考虑)
开始在YahooEngine里面编写获取货币交换率的代码。Engine里面的方法会在ViewController里面调用。一个好的设计实践就是确保你的Engine类不会暴露URL和HTTP的请求头给调用的类。在调用的类中只能向Engine传送参数,其余任何操作都在Engine里操作,所以封装函数时要提前考虑好需要的参数。因为请求都是异步的,应该在block里面返回值,比如:
-(MKNetworkOperation*) currencyRateFor:(NSString*) sourceCurrency
inCurrency:(NSString*) targetCurrency
completionHandler:(CurrencyResponseBlock) completion
errorHandler:(MKNKErrorBlock) error;
MKNetworkEngine父类定义了block的类型如下:
typedef void (^ProgressBlock)(double progress);
typedef void (^ResponseBlock)(MKNetworkOperation* operation);
typedef void (^ErrorBlock)(NSError* error);
在YahooEngine里面,我们使用一种新的block,CurrencyResponseBlock来返回交换率的值,定义如下:
typedef void (^CurrencyResponseBlock)(double rate);
自己封装时要自己定义这个block。
[注]:块的意义在于,可以在实现的时候再次封装数据,在实例化调用的时候解析出来使用。在任何其他app里面,你都应该定义你的block的方法类似于CurrencyResponseBlock这样的来给viewController传回值。
步骤3、处理返回数据
处理数据,就是将从服务器取回的数据(如Json或XML或plist)进行数据类型转换,转换都应该在Engine里面完成。这个时候可以将处理后的model对象或者model对象的数组数据发回。字典数据的key也不要暴露给用户,用户得到的最好只有modal。封装之后程序会很赞。
步骤4、方法实现
现在我们讨论一下计算货币交换率的方法的具体实现细节。
从yahoo获取交换率,就是一个简单的GET请求,用一个宏来定义获取货币率的url请求的格式。
按如下顺序编写engine类方法:
1)构造url和请求参数
//利用宏定义url,利于修改
#defineYAHOO_URL(__C1__, __C2__) [NSString stringWithFormat:@"d/quotes.csv?e=.csv&f=sl1d1t1&s=%@%@=X", __C1__, __C2__]
2)创建一个请求的MKNetworkOperation对象.
//get获取参数
MKNetworkOperation *op = [self
operationWithPath:YAHOO_URL(sourceCurrency, targetCurrency) params:nil httpMethod:@"GET"];
3)设置方法参数
4)添加完成和错误处理方法(即设置operation的completion块和error块),
(在completation块中处理response并转换为模型)
5)可选的,还有请求操作的进度指示。(即添加一个progress块,或者在viewController里面处理)
6)如果你的操作(operation)是下载文件,那么设置一个下载的流(通常是一个文件)给他,这也是可选的
7)当请求操作(operation)完成时,处理结果并且调用block方法来向调用方法返回数据。
下面这段代码设置完完成方法completion和错误处理方法error之后,就将operation通过调用父类的enqueueOperation方法加入队列中,并且返回一个operation引用。
[op addCompletionHandler:^(MKNetworkOperation *completedOperation)
{
// completionBlock 将会被调用两次.
// if you are interested only in new values, move that code within the else block
NSString *valueString = [[completedOperation responseString] componentsSeparatedByString:@","][1];
DLog(@"%@", valueString);
if([completedOperation isCachedResponse]) {
DLog(@"Data from cache %@", [completedOperation responseString]);
}
else {
DLog(@"Data from server %@", [completedOperation responseString]);
}
completionBlock([valueString doubleValue]);
}errorHandler:^(MKNetworkOperation *errorOp, NSError* error) {
errorBlock(error);
}];
[self enqueueOperation:op];
return op;
}
viewController应该持有这个operation并且在 viewController弹出视图体系的时候取消网络操作。所以可在viewDidAppear方法里面调用engine的方法,并且在viewWillDisappear方法里面取消operation。取消操作会释放队列从而使队列继续其他操作(记住,在移动网络中仅仅允许2个并发请求,取消不再需要的operation可以提升性能,加速你的app)
-(void) viewDidDisappear:(BOOL)animated {
if(self.currencyOperation) {
[self.currencyOperation cancel];
self.currencyOperation = nil;
}
}
在ViewController中也可以(可选的)添加进度处理(progress),并且更新界面,代码示例如下:
[self.uploadOperation onUploadProgressChanged:^(double progress) {
DLog(@"%.2f", progress*100.0);
self.uploadProgessBar.progress = progress;
}];
MKNetworkEngine也可以很方便的根据url来创建请求,所以下面代码可以写为:
MKNetworkOperation*op = [self operationWithPath:YAHOO_URL(sourceCurrency, targetCurrency)];
注意请求的url是自动在初始化engine的代码里面加上提供的域名。
以上是GET,那创建一个POST,DELETE或者PUT的方法一样简单,就是更换http方法的参数。