特性
超轻量级
整个应用共享单一队列
严重依赖网络连接的应用应该优化他们的网络并发连接数。十分不幸的是,现在还没有网络库可以正确的完成这些功能。让我来举个例子说明如果你不去优化或者控制网络的并发连接数会发生什么。
Let’s assume that you are uploading a bunch of photos (think Color or Batch) to your server. Most
假如你正在上传一系列的图片(比如Color和 Batch)到服务器。大多数的移动网络(3G)不允许一个给定的IP地址超过两个的并发的http请求。这就是说,在你的设备上,3G网络下,你不能同时打开超过两个的并发HTTP请求。EDGE网络就更差了,大多数情况下你甚至不能打开超过一个的连接。这个限制在传统的wifi的情况下是相当高的(6个)。但是,你的设备并不总是连接到Wifi下,你应该为受限制的网络环境考虑。在最普通的情况下你的设备都是连接到3G网络,就是说你被限制同时只能上传2张图片。现在问题的关键不是上传两张图片时很慢,而是当你上传图片时再打开一个新的View,这个view在加载图片的缩略图的时候。当你不去通过app控制正确的队列大小时,你的缩略图加载操作就会超时,这种现象可不是正确的。正确的做法是把缩略图的加载排好优先级,或者等待上传完成后再加载缩略图。这就要求你的app有一个全局的队列。MKNetworkKit自动的保证你的app的每一个队列的实例使用单一的共享队列。虽然MKNetworkKit自己不是单例的,但是他的共享队列是。
正确的显示网络连接的标志
现在有许多第三方的类使用记录网络调用的次数的方式来控制网络链接标志的显示。但MKNetworkKit使用的是单一共享队列原则来控制网络标志的显示,即通过KVO注册共享队列里正在运行的操作。作为一个开发者,妈妈再也不用担心手动设置网络连接标志的问题了。
if (object == _sharedNetworkQueue && [keyPath isEqualToString:@"operationCount"]) { [UIApplication sharedApplication].networkActivityIndicatorVisible = ([_sharedNetworkQueue.operations count] = 0); }
Auto caching 自动缓存
MKNetworkKit可以自动缓存你的所有GET请求。当你发起同样一个请求的时候,MKNetworkKit会立即用缓存的响应(如果有)来调用完成方法,也会向远程服务器发出一个请求。当服务器的数据返回以后,会用取到的新的相应再次调用完成方法。这就是说,你不需要手动的处理缓存,你需要做的,就只有调用这个方法:[[MKNetworkEngine sharedEngine] useCache];当然,你也可以在你的MKNetworkEngine子类中定制缓存的目录和内存缓存的消耗量。
Operation freezing 操作冻结
用了MKNetworkKit,你就拥有了冻结网络操作的能力。当你冻结一个操作的时候,为了防止网络连接丢失,操作会被自动序列化并且在设备联网之后自动执行。想想微博客户端的草稿箱功能。
Image Caching 图片缓存
MKNetworkKit可以无缝的缓存缩略图。通过重写几个方法,你可以设置缓存多少张图片在内存缓存以及缓存的目录。重写这些方法完全是可选的。
Performance 性能
一个词:速度。MKNetworkKit的缓存是无缝的,就像NSCache一样工作,除此之外,当内存警告的时候,内存缓存会写入到缓存目录中。
How to use 如何使用
OK,不自吹了,让我们来看看如何使用这个framework。
Adding the MKNetworkKit 添加MKNetworkKit
MKNetworkKit 中的类
我相信简洁就是美。苹果已经把实际网络操作的繁重工作都做了,所以第三方的网络库应该提供的就是一个优雅的队列和可选的缓存。我坚信,任何第三方的库都应该少于10个类(不管是网络库还是UIkit的替代库)。多过10个,就是过度。Three 20库就是一个臃肿的例子,ShareKit也是,也许这两个库不错,但是仍然是庞大而且臃肿的。ASIHttpRequest或者AFNetworking比RESTKit而言都是轻量级的,JSONKit比起TouchJSON(或者其他任何TouchCode库)就是轻量级的。也许就我一个人喜欢这样子,但我就是不能忍受我的app里有第三方的库比我的代码还要多。
巨大的库的问题就在于很难去理解他的内在的工作机制,而且很难去根据自己的需求定制。我的添加IAP的MKStoreKit库就是超级易用的而且我相信MKNetWorkKit也是如此。使用MKNetworkKit,你只需要知道MKNetworkOperation 和 MKNetworkEngine两个类所暴露出来的方法。
MKNetworkOperation类似于ASIHttpRequest类,是一个NSOperation的子类并且封装了请求相应类。你需要为你的app的每一个网络请求创建一个MKNetworkOperation。
MKNetworkEngine是一个假单例的类,负责管理你的app的网络队列。因此,简单的请求时,你应该直接使用MKNetworkEngine的方法。在更为复杂的定制中,你应该集成并子类化它。每一个MKNetworkEngine的子类都有他自己的Reachability对象来通知服务器的连通情况。你应该考虑为你的每一个特别的REST服务器请求子类化MKNetworkEngine。因为是假单例模式,每一个单独的子类的请求,都会通过仅有的队列发送。
你可以在应用的delegate里面retain MKNetworkEngine的实例,就像CoreDatademanagedObjectContext类。当你使用MKNetworkKit的时候,你创建一个MKNetworkEngine的子类来从逻辑上分组你的网络请求。就是说,Yahoo相关的请求都在一个类中,Facebook相关的请求都在另一个类中。我们会看到3个不同的使用库的例子。
步骤 1: 创建一个YahooEngine 继承自 MKNetworkEngine.
MKNetworkEngine的初始化方法需要主机名和自定义的header(如果有)。自定义的头是可选的而且可以为nil,如果你正在编写自己的REST服务器(不是现在的情况)你可能需要考虑添加客户端版本以及其他类似客户端标识的元数据。
NSMutableDictionary *headerFields = [NSMutableDictionary dictionary]; [headerFields setValue:@"iOS" forKey:@"x-client-identifier"]; self.engine = [[YahooEngine alloc] initWithHostName:@"download.finance.yahoo.com" customHeaderFields:headerFields];
当你创建一个MKNetworkEngine子类,Reachability的会自动实现。这样当服务器宕机或者其他不可预料的情况下时,请求会被自动的队列或者冻结。想要获取更多关于冻结操作的信息,请阅读后面冻结操作相关的章节。
步骤 2:设计 Engine 类 (分离考虑)
让我们开始在YahooEngine里面编写获取货币交换率的代码。Engine里面的方法会在ViewController里面调用。一个好的设计实践就是确保你的Engine类不会暴露URL和http的请求头给调用的类。你的View层不应该知道url路径以及需要的参数,就是对应着YahooEngine里面的货币及以及货币单位。返回的数据可以为double值表示货币交换率或者时间戳。因为请求都是异步的,你应该在block里面返回这些值,比如:
-(MKNetworkOperation*) currencyRateFor:(NSString*) sourceCurrency inCurrency:(NSString*) targetCurrency onCompletion:(CurrencyResponseBlock) completion onError:(ErrorBlock) error;
typedef void (^ProgressBlock)(double progress); typedef void (^ResponseBlock)(MKNetworkOperation* operation); typedef void (^ErrorBlock)(NSError* error);
在YahooEngine里面,我们使用一种新的block,CurrencyResponseBlock来返回交换率的值,定义如下:
typedef void (^CurrencyResponseBlock)(double rate);
在任何其他app里面,你都应该丁一你的block的方法类似于CurrencyResponseBlock这样的来给viewController传回值。
步骤 3: 处理返回数据
处理数据,就是转换你从服务器取回的数据,不论时Json还是XML或者二进制plist,都应该在Engine里面完成。再次声明,不要让你的Viewcontroller做这件事,你的Engine应该仅仅发回正确的model对象或者model对象的数组。在Engine中转换json或者xml。再次声明,为了确保分类原则,你的viewController应该不知道从json里面获取单个元素的key。
这就是设计Engine的准则了,大部分的网络库不强迫你遵循一些接口分离的原则,但我do,因为我爱你。
步骤4: 方法实现
现在我们讨论一下计算货币交换率的方法的具体实现细节
从yahoo获取交换率,就是一个简单的GET请求,我写了一个宏来定义获取货币率的url请求的格式
#define YAHOO_URL(__C1__, __C2__) [NSString stringWithFormat:@"d/quotes.csv?e=.csv&f=sl1d1t1&s=%@%@=X", __C1__, __C2__]
MKNetworkOperation *op = [self operationWithPath:YAHOO_URL(sourceCurrency, targetCurrency) params:nil httpMethod:@"GET"]; [op onCompletion:^(MKNetworkOperation *completedOperation) { DLog(@"%@", [completedOperation responseString]); // do your processing here completionBlock(5.0f); }onError:^(NSError* error) { errorBlock(error); }]; [self enqueueOperation:op]; return op;[/pre]
[self.uploadOperation onUploadProgressChanged:^(double progress) { DLog(@"%.2f", progress*100.0); self.uploadProgessBar.progress = progress; }];
MKNetworkOperation *op = [self operationWithPath:YAHOO_URL(sourceCurrency, targetCurrency)];
示例
2:
上传图片到服务器(比如TwitPic)
现在我们看一个如何上传图片到服务器的例子,上传图片明显需要操作把data编码为表格请求。MKNetworkKit遵循一系列的类似ASIHttpRequest的请求。
你可以调用addFile:forKey:在MKNetworkOperation里面来添加文件附件作为请求表格的数据。很简单。
MKNetworkOperation 也有一个简单的方法来从NSData指针中添加图片,就是调用addData:forKey: 方法来直接从NSData上传图片。 (比如直接从相机添加图片).
例子
3:
下载文件到本地目录(缓存)
用MKNetworkKit从远程服务器下载文件并且保存到用户的iPhone的某个地方是超级简单的
仅仅需要设置MKNetworkOperation的outputStream即可:
[operation setDownloadStream:[NSOutputStream outputStreamToFileAtPath:@"/Users/mugunth/Desktop/DownloadedFile.pdf" append:YES]];
例子
4:
图片缩略图缓存。
为了下载图片,你可能需要提供绝对的url而不是一个相对目录
MKNetworkEngine有一个便捷的方法。只需要调用operationWithURLString:params:httpMethodMKNetworkEngine 来用绝对url创建个一个请求,MKNetworkEngine是智能的,它会合并多个get请求到同一个url并且当操作完成时通知所有的block,这极大的提高了获取缩略图的速度。
子类 MKNetworkEngine 并且重写图片缓存目录和缓存级别,如果你不想自定义这两个参数,你只需要调用MKNetworkEngine的方法来下载图片即可,实际上我也比较推荐这种方法,。
缓存操作
MKNetworkKit默认缓存所有的请求。你需要做的仅仅是在你的Engine上打开缓存。当GET请求执行时,如果响应之前被缓存过,你的完成处理代码几乎是立即会被调用并传递缓存过的相应,要知道请求是否被缓存,调用isCachedResponse方法,比如下面
[op onCompletion:^(MKNetworkOperation *completedOperation) { if([completedOperation isCachedResponse]) { DLog(@"Data from cache"); } else { DLog(@"Data from server"); } DLog(@"%@", [completedOperation responseString]); }onError:^(NSError* error) { errorBlock(error); }];
冻结操作
可以确定的, MKNetworkKit的最又去的功能就是内置的冻结操作的功能。所有你需要做的就是设置请求操作为freezable,不用费任何力气!
[op setFreezable:YES];
MKNetworkOperation中的便捷方法
MKNetworkOperation 提供了一些如下便捷方法来方便你格式化你的响应数据
方便宏定义
宏定义Dlog和ALog是我不知羞耻的从stackoverflow上偷的,而且找不到源文件了,如果时你写的,请让我知道
关于GCD
我故意没用gcd,因为网络请求需要随时停止和安排优先级,gcd打给你然比NSOperationQueue更高效,但是不能做到上面两点。我不推荐在网络请求的队列中使用gcd。
关于文档
头文件都加了注释,而且我正在尝试整理,于此同事,你可以随时玩弄代码。
源代码
源代码和Demo工程都在Github,连接:MKNetworkKit
on Github
关于新增特性
请不要email添加新特性,最好的方式是在github上添加issue
许可证
MKNetworkKit is licensed under MIT
License
All of my source code can be used free of charge in your app, provided you add the copyright notices to
your app. A little mention on one of your most obscure “about” page will do.
Attribution free licensing available upon request. Contact me at mknetworkkit@mk.sg
iOS Framework: Introducing MKNetworkKit,布布扣,bubuko.com
iOS Framework: Introducing MKNetworkKit
原文:http://blog.csdn.net/a271246498/article/details/25335735