在这里我们将讨论MKNetworkKit基本特性,以及常用操作(在Demo里面实现),实现GET、POST请求数据,以及断点下载(缓存目录、下载目录的设置)与上传文件。Demo链接:http://download.csdn.net/detail/wlnana17/7940595
什么是 MKNetworkKit?
MKNetworkKit 是一个用objective-c写的网络库,具有无缝连接,基于block,ARC支持以及易用等特点。
MKNetworkKit的灵感来自于其他两个流行的网络库:ASIHTTPRequest和AFNetworking,结合了两个库的共同特点,并且有一些新的特性。除此之外,MKNetworkKit可能会比其他网络库而言为了代码的清晰性,要求你写一丁点多的代码。用了MKNetworkKit,你很难写出丑陋的网络代码。
特性
1. 高度的轻量级,仅仅只有2个主类
MKNetworkEngine与MKNetworkOperation
MKNetworkOperation与ASIHttpRequest相似。这是一个NSOperation的子类,包装你的请求和响应类。创建一个MKNetworkOperation用于管理应用内请求时序等问题。
MKNetworkEngine是一个伪单例类,负责管理你的app的网络队列。因此,简单的请求时,你应该直接使用MKNetworkEngine的方法。在更为复杂的定制中,你应该继承它。每一个MKNetworkEngine的子类都有他自己的Reachability对象来通知服务器的连通情况。可以考虑为特别的REST服务器请求都通过继承MKNetworkEngine。因为是伪单例模式,每一个单独的子类的请求,都会通过仅有的队列发送。
2. 自主操作多个网络请求
移动网络不允许同时超过两个并发网络请求。所以当3G网络时你的队列大小应该设为2,MKNetworkKit自动为你处理这些。当网络进入3G/EDGE/GPRS时,它会更改并发连接的数目为2,并且在连接wifi时自动设置回6。有了这个特性,你会看到当你通过3G网络从服务器加载缩略图(或者多个小的请求)时有巨大的性能提升
3.更加准确的显示网络活动指标;
因为MKNetworkKit采用共享单一队列的机制,多个MKNetworkEngine对象只有一个NSOperationQueue队列,所以可以更准确的知道共享队列里正在运行的操作。
4.自动设置网络速度,实现自动的2G、3G、wifi切换;
5.冻结操作
自动缓冲技术的完美应用,实现网络操作记忆功能,当你掉线了又上线后,会继续执行未完成的网络请求;
//冻结操作:会在网络不通时自动的被序列化并且上线后自动执行
[op setFreezable:YES];
6.准确无误的成功执行一次网络请求,摒弃后台的多次请求浪费;
7.打开缓存
//开启使用缓存
[engine useCache];
8.支持ARC机制;
9.在整个app中可以只用一个队列(queue),队列的大小可以自动调整。
假如你正在上传一系列的图片(比如Color和 Batch)到服务器。大多数的移动网络(3G)不允许一个给定的IP地址超过两个的并发的http请求。这就是说,在你的设备上,3G网络下,你不能同时打开超过两个的并发HTTP请求。EDGE网络就更差了,大多数情况下你甚至不能打开超过一个的连接。这个限制在传统的wifi的情况下是相当高的(6个)。但是,你的设备并不总是连接到Wifi下,你应该为受限制的网络环境考虑。在最普通的情况下你的设备都是连接到3G网络,就是说你被限制同时只能上传2张图片。现在问题的关键不是上传两张图片时很慢,而是当你上传图片时再打开一个新的View,这个view在加载图片的缩略图的时候。当你不去通过app控制正确的队列大小时,你的缩略图加载操作就会超时,这种现象可不是正确的。正确的做法是把缩略图的加载排好优先级,或者等待上传完成后再加载缩略图。这就要求你的app有一个全局的队列。MKNetworkKit自动的保证你的app的每一个队列的实例使用单一的共享队列。虽然MKNetworkKit自己不是单例的,但是他的共享队列是。
MKNetworkOperation中的便捷方法
MKNetworkOperation提供了一些如下便捷方法来方便你格式化你的响应数据
- responseData
- responseString
- responseJSON (Only on iOS 5 以上)
- responseImage
- responseXML
- error
使用方法
1. 拖拽MKNetworkKit的目录到你的工程里
2. 添加 CFNetwork.Framework, SystemConfiguration.framework andSecurity.framework依赖库
3. 在PCH文件中包含 MKNetworkKit.h
4. 删除 NSAlert+MKNetworkKitAdditions.h如果你开发的是iOS程序。
删除 UIAlertView+MKNetworkKitAdditions.h如果你开发的是Mac程序
MKNetworkKit给我们提供了常用且非常简单的借口,可以实现我们的常用操作,如果有复杂的网络操作,可以子类化MKNetworkEngine以及MKNetworkOperation,重写它的方法来实现想要的功能。
DEMO
光看上面的概念对初学者来说可能很抽象,下面我们来做一个Demo实例化上面的抽象概念。
GET请求
//1.创建MKNetworkEngine对象, 会自动添加http://
if (getEngine == nil) {
getEngine = [[MKNetworkEngine alloc] initWithHostName:kWeatherHostName];
//开启使用缓存
[getEngine useCache];
}
//2.创建MKNetworkOperation对象, 这里的path 将 hostName 作为前缀,ssl为YES表示用https://
MKNetworkOperation *op = [getEngine operationWithPath:kWeatherPath params:nil httpMethod:@"GET" ssl:NO];
//3.指定请求代码块,成功时回调CompletionHandler,失败时回掉errorHandler
[op addCompletionHandler:^(MKNetworkOperation *completedOperation) {
//是否使用缓存
if ([completedOperation isCachedResponse]) {
NSLog(@"GET FROM CACHE");
}else{
NSLog(@"GET FROM SERVER");
}
//是主线程
NSLog(@"是否是主线程:%d",[NSThread isMainThread]);
//3.1 通过responseData方法
// NSDictionary *dic = [[NSJSONSerialization JSONObjectWithData:completedOperation.responseData options:NSJSONReadingMutableContainers error:NULL] objectForKey:@"weatherinfo"];
//3.2 通过responseJSON方法
NSDictionary *dic = [[completedOperation responseJSON] objectForKey:@"weatherinfo"];
//将字典转换成模型对象
WeatherModel *model = [[WeatherModel alloc] initContentWithDic:dic];
_textView.text = [NSString stringWithFormat:@"地区:%@\n编号:%@\n温度:%@\n时间:%@",model.city,model.cityid,model.temp,model.time];
} errorHandler:^(MKNetworkOperation *completedOperation, NSError *error) {
NSLog(@"GET 错误: %@",error.localizedDescription);
}];
//4.添加到队列,发起网络请求
//forceRelodad : NO 与enqueueOperation一样,YES 表示即使缓存数据是可用的,也不会返回缓存数据。
[getEngine enqueueOperation:op forceReload:NO];
POST请求
//请求头
// NSDictionary *headers = [NSDictionary dictionaryWithObjectsAndKeys:@"zh-cn",@"Accept-Language",
// @"GBK,utf-8",@"Accept-Charset",nil];
//设置POST请求体
NSDictionary *param = @{@"username": @"admin",
};
if (postEngine == nil) {
postEngine = [[MKNetworkEngine alloc] initWithHostName:@"127.0.0.1:5558" apiPath:nil customHeaderFields:nil];
}
//设置请求体
MKNetworkOperation *op = [postEngine operationWithPath:@"/s" params:param httpMethod:@"POST"ssl:NO];
[op addCompletionHandler:^(MKNetworkOperation *completedOperation) {
[completedOperation responseJSONWithOptions:NSJSONReadingMutableContainers completionHandler:^(id jsonObject) {
//用这个方法可根据指定的选项返回json数据
}];
} errorHandler:^(MKNetworkOperation *completedOperation, NSError *error) {
NSLog(@"POST 错误: %@",error.localizedDescription);
}];
[postEngine enqueueOperation:op];
DOWNLOAD下载
//下载目录
NSString *downloadPath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];
downloadPath = [downloadPath stringByAppendingString:@"/freja.jpg"];
NSLog(@"%@",downloadPath);
//子类化了一个MKNetworkEngine类型
downloadEngine = [DownloadEngine sharedDownloadEngine];
__weak RootViewController *weakVC = self;
//设置成功Block
[downloadEngine setCompletionHandler1:^(MKNetworkOperation *op) {
RootViewController *strongVC = weakVC;
if (strongVC) {
strongVC->_textView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageWithContentsOfFile:downloadPath]];
}
}];
//设置出错Block
[downloadEngine setErrorHandler1:^(MKNetworkOperation *op, NSError *error) {
NSLog(@"DOWNLOAD 错误: %@",error.localizedDescription);
}];
//设置下载进度变化的Block
[downloadEngine setProgressChanged1:^(double progress) {
RootViewController *strongVC = weakVC;
if (strongVC) {
strongVC->_downProgress.progress = progress;
strongVC->_downloadLabel.text = [NSString stringWithFormat:@"%.1f",progress*100];
}
}];
//开始下载
[downloadEngine startOperationUrlString:kDownloadUrlStr DownloadPath:downloadPath IsRewrite:YES];
UPLOAD上传
if (uploadEngine == nil) {
uploadEngine = [[MKNetworkEngine alloc] initWithHostName:@"127.0.0.1:5558"];
}
//下载目录的图片
NSString *downloadPath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];
downloadPath = [downloadPath stringByAppendingString:@"/freja.jpg"];
NSFileManager *filemanager = [NSFileManager defaultManager];
if (![filemanager fileExistsAtPath:downloadPath]) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"没有文件" message:@"请先下载" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles: nil];
[alert show];
return;
}
NSDictionary *params = @{@"username" : @"admin"};
MKNetworkOperation *op = [downloadEngine operationWithPath:@"upload.jsp" params:params httpMethod:@"POST"];
[op addFile:downloadPath forKey:@"freja"];
//冻结操作:会在网络不通时自动的被序列化并且上线后自动执行
[op setFreezable:YES];
[op addCompletionHandler:^(MKNetworkOperation *completedOperation) {
NSLog(@"上传成功:%@",completedOperation.responseString);
} errorHandler:^(MKNetworkOperation *completedOperation, NSError *error) {
NSLog(@"UPLOAD 错误 : %@",error.localizedDescription);
}];
[uploadEngine enqueueOperation:op];