1.什么是MKNetWorkKit?
MKNetWorkKit是一个用OC语言编写的网络框架,支持block块和ARC;并且MKNetWorkKit的用法简单.
MKNetWorkKit是集成了ASIHTTPRequest和 AFNetworking
两个框架于一体,在集成两者的优点之外,自己还增加了很多新的特性.
2. MKNetWorkKit的优点
1、整个框架只有一些类别方法和两个类(MKNetworkEngine和MKNetworkOperation)所以它使用起来很简便
2、自主操作多个网络请求;
3、更加准确的显示网络活动指标;
4、自动设置网络速度,实现自动的2G、3G、wifi切换;
5、自动缓冲技术的完美应用,实现网络操作记忆功能,当你掉线了又上线后,会继续执行未完成的网络请求;
6、可以实现网络请求的暂停功能;
7、准确无误的成功执行一次网络请求,摒弃后台的多次请求浪费;
8、支持图片缓冲;
9、支持ARC机制;
10、在整个app中可以只用一个队列(queue),队列的大小可以自动调整。
3.如何配置MKNetworkKit?
1、从https://github.com/MugunthKumar/MKNetworkKit下载MKNetworkKit;
2、将下载包中的 MKNetWorkKit 文件夹拖到你新建的工程中;
3、在项目设置中添加:SystemConfiguration.framework,CFNetwork.framework,Security.framework和ImageIO.framework
4.怎么进行网络请求?
MKNetworkKit中主要有两个类:MKNetworkOperation和MKNetworkEngine。MKNetworkOperation是NSOperation的子类并且封装了请求相应类,我们需要为每一个网络请求创建一个MKNetworkOperation。MKNetworkEngine负责管理网络队列,对于简单的请求,我们应该直接使用MKNetworkEngine的方法,对于复杂的需求,我们可以子类化MKNetworkEngine。
5.MKNetworkKit中的一些简便用法
MKNetworkKit的一些简便用法:
1. responseData
2. responseString
3. responseJSON (Only on iOS 5以上)
4. responseImage
5. responseXML
6. error
6.一个利用MKNetworkKit网络请求(GET请求)的天气预报DEMO
效果图:
//请求路径.是在主机名之后显示的,可以与主机名进行拼接,拼接成一个完整的url
NSString *path = [[NSString alloc] initWithFormat:@"//data/sk/%@.html",cityID];
//创建一个MKNetworkEngine对象,注意initWithHostName后面是主机名
//.....MKNetworkEngine负责管理网络队列NSOperationQueue
__block MKNetworkEngine *engine = [[MKNetworkEngine alloc] initWithHostName:@"www.weather.com.cn" customHeaderFields:nil];
//创建一个MKNetworkOperation对象
//MKNetworkOperation是NSOperation的子类并且封装了请求相应类
//在进行网络请求是需要为每一个网络请求创建一个MKNetworkOperation
MKNetworkOperation *op = [engine operationWithPath:path params:nil httpMethod:@"GET"];
//指定请求的代码块,网络请求成功时回调代码块addCompletionHandler,失败时回调errorHandler的block代码块
[op addCompletionHandler:^(MKNetworkOperation *completedOperation) {
//通过MKNetworkOperation中的responseData方法直接获取url中的数据.并且存放在NSData中
// NSData *data = [completedOperation responseData];
// //对拿到的数据进行json解析,系统给出的json解析
// result = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
// result = [result objectForKey:@"weatherinfo"];
//利用MKNetworkKit给的json解析进行解析数据
result = [[completedOperation responseJSON] objectForKey:@"weatherinfo"];
self.cityLabel.text = [result objectForKey:@"city"];
self.tempLabel.text = [result objectForKey:@"temp"];
self.wdLabel.text = [result objectForKey:@"WD"];
self.wlLabel.text = [result objectForKey:@"WS"];
self.sdLabel.text = [result objectForKey:@"SD"];
self.timeLabel.text = [result objectForKey:@"time"];
} errorHandler:^(MKNetworkOperation *completedOperation, NSError *error) {
NSLog(@"%@",[error localizedDescription]);
engine = nil;
}];
//发起网络请求
[engine enqueueOperation:op];
post请求
// 转成专门用于URL的格式www.weather.com.cn/data/sk/101010300.html 101010300是城市ID
NSString *host = @"www.weather.com.cn";
// 域名(host)后面跟着的路径,
NSString *path = [NSString stringWithFormat:@"//data/sk/%@.html",cityID];
// 目标URL:www.weather.com.cn/data/sk/101010300.html
// 需要发送的参数
NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
[params setValue:cityID forKey:@"cityID"];
// path 值可以放到 engine 的初始化中,也可以放到 operation 的初始化中,效果一样
MKNetworkEngine *engine = [[MKNetworkEngine alloc] initWithHostName:host apiPath:path customHeaderFields:nil];
MKNetworkOperation *operation = [engine operationWithPath:nil params:params httpMethod:@"POST"];
// 添加网络请求完成处理逻辑
[operation addCompletionHandler:^(MKNetworkOperation *completedOperation) {
NSLog(@"POST请求完成");
self.wetherText.text = [completedOperation responseString];
} errorHandler:^(MKNetworkOperation *completedOperation, NSError *error) {
NSLog(@"POST请求出错");
self.wetherText.text = [NSString stringWithFormat:@"请求出错: %@", error];
}];
// 发送网络请求
[engine enqueueOperation:operation];
下载文件
- (IBAction)LoadButton:(UIButton *)sender {
//获取缓存路径.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cachepath = [paths objectAtIndex:0];//得到缓存的路径
//进行拼接得到文件下载后缓存的路径
NSString *downloadPath = [cachepath stringByAppendingString:@"mmm.zip"];
[_engine addDownLoadTaskInQueue:url tofilePath:downloadPath breakpointResum:YES
rewriteFile:(BOOL)NO];
}
- (IBAction)pauseButton:(UIButton *)sender {
[_engine cancelDownloadFileTaskInQueue:url];
}
- (IBAction)deleteButton:(UIButton *)sender {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cachepath = [paths objectAtIndex:0];//得到缓存的路径
//进行拼接得到文件下载后缓存的路径
NSString *downloadPath = [cachepath stringByAppendingString:@"mmm.zip"];
NSFileManager *fileManage = [NSFileManager defaultManager];
if ([fileManage fileExistsAtPath:downloadPath]) {
[fileManage removeItemAtPath:downloadPath error:nil];
}
}
#import "MKNetworkEngine.h"
@class DownLoadEngine;
@class DownLoadOperation;
@protocol DownLoadEngineDelegate
//创建一个改变progress的方法
- (void)changeprogress:(double)changeProgress
withOperation:(DownLoadOperation *)operation
withEngine:(DownLoadEngine *)engine;
//下载完成时
- (void)downloadEngineDidFinsh:(DownLoadEngine*)engine
withOperation:(DownLoadOperation *)operation;
//下载任务已经存在
- (void)downloadEngineDownloadExist:(DownLoadEngine *)engine
withURL:(NSString *)paramURL;
//下载文件已经存在
- (void)downloadEngineDownloadDone:(DownLoadEngine *)engine
withURL:(NSString *)paramURL;
//暂停下载
- (void)downloadEnginePauseTask:(DownLoadEngine *)engine
withURL:(NSString *)paramURL;
@end
@interface DownLoadEngine : MKNetworkEngine
@property(nonatomic,retain)NSMutableArray *allDownloads;//用来存放任务的数组
@property(nonatomic,assign)id<DownLoadEngineDelegate> delegate;
//DownLoadEngine的单例方法
+ (id)sharDownLoadEngine;
//暂停所有任务的方法
- (void)cancelAllOperations;
//将所有的下载任务放到一个队列中
- (void)addDownLoadTaskInQueue:(NSString *)urlString//要下载的文件的url路径
tofilePath:(NSString *)paramPathparamFilePath是下载的文件下载完存放的路径.
breakpointResum:(BOOL)resum
rewriteFile:(BOOL)paramRewrite;//是否支持断点续传
- (void)cancelDownloadFileTaskInQueue:(NSString *)paramURL;//暂停或取消指定的任务的方法
- (void)addDownLoadTaskInQueue:(NSString *)urlString
tofilePath:(NSString *)paramPath
breakpointResum:(BOOL)resum
rewriteFile:(BOOL)paramRewrite
{
//获得临时文件的路径
// 获取主目录下的tmp目录路径,用来存放下载的文件的临时文件(缓存路径)
NSString *temPath = NSTemporaryDirectory();
NSCharacterSet *set = [NSCharacterSet characterSetWithCharactersInString:@"/"];
NSRange lastRange = [paramPath rangeOfCharacterFromSet:set options:NSBackwardsSearch];
//拼接得到下载文件的缓存目录
NSString *temfilePath = [NSString stringWithFormat:@"%@%@.temp",temPath,[paramPath substringFromIndex:lastRange.location+1]];
//创建operation
DownLoadOperation *operation = [DownLoadOperation operationUrlWithString:urlString
params:nil httpMethod:@"GET" tempFilePath:temfilePath downloadFilePath:paramPath
rewriteFile:paramRewrite];
//判断文件是否下载
//创建一个BOOL值
BOOL exitsDownLoad = NO;
for (DownLoadOperation *op in self.allDownloads) {
if ([op.url isEqualToString:operation.url]) {
exitsDownLoad = YES;
NSLog(@"正在下载");
}
}
if (exitsDownLoad) {
[[self delegate] downloadEngineDownloadExist:self withURL:urlString];
}else if (operation == nil ){
[[self delegate] downloadEngineDownloadDone:self withURL:urlString];
}else
{
[self enqueueOperation:operation];//发起网络请求
[self.allDownloads addObject:operation];
//onDownloadProgressChanged:^(double progress)此方法为MKNetworkKit中的方法
//下载进度改变时回调方法downloadManager: withOperation: changeProgress:
[operation onDownloadProgressChanged:^(double progress) {
[[self delegate] changeprogress:progress withOperation:operation withEngine:self];
}];
//当任务完成都回调此方法.将下载在缓存中的文件移到指定的目录中存放
[operation onCompletion:^(MKNetworkOperation *completedOperation) {
NSFileManager *fileManager =[[NSFileManager alloc] init];
NSError *error = nil;
// 下载完成以后 先删除之前的文件 然后mv新的文件
//fileExistsAtPath判断paramFilePath是否存在,即是否下载完成
if ([fileManager fileExistsAtPath:paramPath]) {
[fileManager removeItemAtPath:paramPath error:&error];
if (error) {
exit(-1);
}
}
//判断paramFilePath是否存在,若存在则将其移到tempFilePath文件中
[fileManager moveItemAtPath:temfilePath toPath:paramPath error:&error];
if (error) {
exit(-1);
}
//将operation从数组中移除
[[self delegate] downloadEngineDidFinsh:self withOperation:(DownLoadOperation *)completedOperation];
[self.allDownloads removeObject:operation];
} onError:^(NSError *error) {
NSLog(@"出错了");
}];
}
}
//暂停下载
- (void)cancelDownloadFileTaskInQueue:(NSString *)urlString
{
DownLoadOperation *deleteOperation = nil;
for (DownLoadOperation *op in self.allDownloads) {
if ([op.url isEqualToString:urlString]) {
deleteOperation = op;
}
}
[[self delegate] downloadEnginePauseTask:self withURL:urlString];
[deleteOperation cancel];
[self.allDownloads removeObject:deleteOperation];
}
//暂停所有的下载'
- (void)cancelAllOperations
{
for (DownLoadOperation *op in self.allDownloads) {
[op cancel];
}
[self.allDownloads removeAllObjects];
}
子类化的MKNetworkOperation:
#import "MKNetworkOperation.h"
@interface DownLoadOperation : MKNetworkOperation
{
NSString *tempFilePath;
NSString *downloadFilePath;
}
//tempFilePath:(NSString *)tempFilePath下载文件时存放缓存路径
//downloadFilePath:(NSString *)downloadFilePath文件完后存放的路径
+(DownLoadOperation *)operationUrlWithString:(NSString *)urlString
params:(NSMutableDictionary *)params
httpMethod:(NSString *)method
tempFilePath:(NSString *)tempFilePath
downloadFilePath:(NSString *)downloadFilePath
rewriteFile:(BOOL)rewrite;
.m文件
+(DownLoadOperation *)operationUrlWithString:(NSString *)urlString
params:(NSMutableDictionary *)params
httpMethod:(NSString *)method
tempFilePath:(NSString *)tempFilePath
downloadFilePath:(NSString *)downloadFilePath
rewriteFile:(BOOL)rewrite
{
//获得缓存的路径
// 创建文件管理器
NSFileManager *fileMgr = [NSFileManager defaultManager];
//初始化消息头
NSMutableDictionary *headersDic = [[NSMutableDictionary alloc] init];
//下载文件时或重新下载时
//首先判断缓存中是否有下载中的文件,如果有删除,没有则到文件下载完成后存放的路径中查看是否有下载好的文件,若有将其删除
//断点续传的关键在于rewriteFile:(BOOL)rewrite这个BOOL值..
if (rewrite &&[fileMgr fileExistsAtPath:tempFilePath]) {
// NSError *error = nil;
// UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"" message:@"文件已经存在是否继续下载" delegate:self cancelButtonTitle:@"确定" otherButtonTitles:@"取消", nil];
// [alert show];
[fileMgr removeItemAtPath:tempFilePath error:nil];
}else if (rewrite &&[fileMgr fileExistsAtPath:downloadFilePath]){
NSError *error = nil;
[fileMgr removeItemAtPath:downloadFilePath error:&error];
}
//判断文件是否下载
//若没有下载则下载文件.并构建下载进度.下载中则返回空
if ([fileMgr fileExistsAtPath:downloadFilePath]) {
return nil;
}else {
//[[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString *)kCFBundleNameKey]是获得该工程下载文件的
//[[[NSBundle mainBundle] infoDictionary]objectForKey:(NSString *)kCFBundleVersionKey]]获得版本号
NSString *userAgentString = [NSString stringWithFormat:@"%@/%@",
[[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString *)
kCFBundleNameKey],
[[[NSBundle mainBundle] infoDictionary]objectForKey:(NSString *)kCFBundleVersionKey]];
[headersDic setObject:userAgentString forKey:@"momo"];
//判断之前是否下载 若下载则重新构造header(消息头)
if ([fileMgr fileExistsAtPath:tempFilePath]) {
NSError *error = nil;
//通过计算大小可以算出下载到那里暂停的,继续下载时会从之前暂停的地方继续下载
unsigned long long fileSize = [[fileMgr attributesOfItemAtPath:tempFilePath error:&error]fileSize];
if (error) {
NSLog(@"get %@ fileSize failed!\nError:%@", tempFilePath, error);
}
NSString *headerRange = [NSString stringWithFormat:@"bytes=%llu-", fileSize];
[headersDic setObject:headerRange forKey:@"range"];
}
//初始化opertion(DownLoadOperation)
DownLoadOperation *opertion = [[DownLoadOperation alloc]
initWithURLString:urlString
params:params
httpMethod:method];
[opertion addDownloadStream:[NSOutputStream outputStreamToFileAtPath:tempFilePath append:YES]];//下载文件的流使用NSOutputStream可以将网络请求的资源回来的数据保存到本地文件
[opertion addHeaders:headersDic];
return opertion;
}
}