MKNetWorkKit(转载)

 

ASIHTTPRequest (作者:BenCopsey) 是一个使用简单,可用于各种从简单到复杂的 HTTP 请求,或者可用于处理 Amazon
S3、Rackspace 等REST 服务的强大框架。

不幸的是,Ben 早在 2011 年 9 月 21
日就已经声明停止开发和支持该框架(见http://allseeing-i.com/%5Brequest_release%5D; )。

Ben 推荐了许多可替代的框架(比如AFNetworking, RestKit 或 LRResty)。但最有潜力的莫过于Mugunth Kumar 的
MKNetworkKit 。Mugunth 曾发布了许多高质量的开源的 iOS/Mac 代码(比如 MKStoreKit),其中值得推荐一个就是
ASHTTPRequest 的替代者: MKNetworkKit。它支持 ARC 和块,易于使用且极为高效。

以下内容摘自
Mugunth自己的博客。原文位于:http://blog.mugunthkumar.com/products/ios-framework-introducing-mknetworkkit。

假设有一个网络框架,它能自动为你缓存 respones,能在你离线时自动记忆你的操作,你觉得怎样?

当你离线时,你可以收藏某个 tweet 页或者标记某个 feed
为已读,当你再次上线时,网络框架会自动执行你的这些操作,这一切都不需要你额外编写代码。请看我对于MKNetworkKit 框架的介绍。

什么是MKNetworkKit?

MKNetworkKit是一个 O-C 编写的网络框架,支持块,ARC 且用法简单。

MKNetworkKit 集 ASIHTTPRequest 和 AFNetworking
两个框架于一体。在集成二者的优秀特性之外,还增加了一堆新的功能。尤其是,相比起其它框架,它能让你更轻松地编写代码。它让你彻底远离那些恶心的网络代码。

特点

超轻量级框架

整个框架只有 2 个类和一些类别方法。因此,它的使用极其简单。

在整个程序中只有一个全局队列

高度依赖互联网连接的 app
应该优先考虑网络线程的并发数。不幸的是,没有任何网络框架在这方面做得够好。因此,一旦你在程序中没有控制好网络线程的并发数,就极易导致出错。

假设你要上传一堆图片到服务器上。绝大多数移动网络(3G)不会允许你对同一个IP 地址的 HTTP 并发连接数超过 2 个。换句话说,在设备上,你不能从
3G 网络中获得 2 个以上的 HTTP 并发连接。对于 Edge 则更糟,大多数情况不能超过1 个。相比较家用宽带网络(Wifi),则这个限制要宽得多(6
个)。但是,你不可能总是使用 wifi,你必须也考虑到有限网络(窄带)的连通性。更多的时候,iDevice设备几乎都能连接到 3G 网络,因此,你同时只能上传
2 张图片。但是,真正的问题不是缓慢的上传速度,而是另一种情况。在你打开一个 view
试图加载缩略图(不同的view)时,上传线程被运行到后台。如果你没有控制好上传队列中的线程数,你的缩略图会加载超时。这是不正常的。正确的方式是优化缩略图加载线程,或者让线程等待直到上传完成再加载缩略图。这需要你在整个程序中只拥有一个queue
队列。

MKNetworkKit 在它的每个实例中使用单例来保证这一点。并不是说MKNetworkKit 是单例的,而是说它的共享队列是单例的。

正确显示网络状态指示

许多第 3
方框架都通过一个“网络连接数增加/减少”的方法回调来显示网络状态,MKNetworkKit则由于使用了单例的共享队列,能自动显示网络状态。在共享队列中有一个线程通过
KVO 方式会随时观察 operationCount 属性。因此对于开发者,一般情况下根本不需要操心网络状态的显示。




if (object == _sharedNetworkQueue && [keyPath
isEqualToString:@"operationCount"]) {

[UIApplication
sharedApplication].networkActivityIndicatorVisible =         ([_sharedNetworkQueue.operations
count] < 0);

}

自动改变队列大小

如前所述,绝大部分移动网络不允许 2 个以上的并发连接,因此你的队列大小在3G 网络下应当设置为 2。 MKNetworkKit
会自动为你处理好这个。当网络出于3G/EDGE/GPRS 时,它会将并发数调整到 2。当网络处于 Wifi 网络时,则自动调整到 6。当你通过 3G
网络中从远程服务器加载缩略图时,这种调整能带来极大的好处。

自动缓存

MKNetworkKit 能自动缓存你所有的 GET 请求。当你再次发起同样的请求时,MKNetworkKit 随即就能调用
response缓存(如果可用的话)传递给 handler 进行处理。当然,它同时也向服务器发出请求。一旦获得服务器数据,handler
被再次要求处理新获取的数据。也就是说,你不用手动缓存。你只需要使用:





[[MKNetworkEngine
sharedEngine] useCache];

当然,你可以覆盖这个方法(子类化),定制你的缓存路径和缓存占用的内存开销。

冻结网络操作

MKNetworkKit 能够“冻结”网络操作。在一个网络操作被“冻结”的情况下,一旦网络连断开,它们将自动序列化并在设备再次连线时自动被提交一次。类似
twitter 客户端的“drafts”。

当你提交一篇 tweet 时,如果网络被标记为“可冻结”,MKNetworkKit 会自动执行冻结并储存这些请求。因此会在将来推迟发送这篇
tweet。整个过程不需要你写一行代码。这个特性你可以用于其他操作,诸如收藏一篇 tweet 或者从 Goolge reader
客户端共享一个帖子,加一个链接到Instapaper 中,等等。

类似的请求只执行一个操作

当你加载缩略图(针对 twitter
stream)时,你最终得为每个实际的图片创建一个新的请求。实际上你所进行的多个请求都是同一个URL。MKNetworkKit 对于队列中的每个 GET
请求都只会执行一次。它还不能到缓存 POST 请求。

图片缓存

MKNetworkKit
内置了缩略图缓存。只要覆盖几个方法,就可以设置内存中最大能缓存的图片数量,以及缓存要保存到目录。当然,你也可以不覆盖这些方法。

性能

即速度。MKNetworkKit 缓存是内置的,就如 NSCache,当发现有内存警告,缓存到内存中的数据将被写入缓存目录。

完全支持 ARC

一般你只会在新项目中使用新的网络框架。MKNetworkKit并不意味着要放弃已有的框架(当然你也可以放弃,这会是个乏味的工作)。对于新的项目,你总是想使用
ARC。当你看到本文的时候,很可能 MKNetworkKit  会是仅有的完全支持 ARC 的网络框架。ARC 通常比非 ARC 代码更快。

用法

Ok,我就不“自卖自夸”了。让我们立即了解如果使用这个框架。

添加MKNetworkKit

  1. 将 MKNetworkKit 目录拖到项目中

  2. 添加下列框架: CFNetwork.Framework, SystemConfiguration.framework,
    Security.framework and ImageIO.Framework.

  3. 将 MKNetworkKit.h 头文件包含到 PCH 文件中

  4. 对于 iOS,删除 NSAlert+MKNetworkKitAdditions.h

  5. 对于 Mac,删除 UIAlertView+MKNetworkKitAdditions.h

总共只需要 5 个核心文件,真是一个强大的网络开发包

MKNetworkKit 的类

  1. MKNetworkOperation

  2. MKNetworkEngine

  3. 一些工具类 (Apple 的 Reachability) 以及类别

我喜欢简单。苹果已经写了最基本最核心的网络代码。第 3 方框架需要的是提供一个优雅的网络队列最多再加上缓存。我认为第3 方框架不应该超过 10
个类(无论它是网络的还是 UIKit 还是别的什么)。超过这个数就太臃肿了。Three20 就是一个例子。现在 ShareKit
又是这样。尽管它们是优秀的,但仍然是庞大和臃肿的。ASIHttpRequest or AFNetworking 比 RESTKit
更轻,JSONKit比TouchJSON (或者任何 TouchCode
库)更轻。这只是我自己的看法,但当一个第三方库的代码超过程序源代码1/3,我就不会使用它。

框架臃肿带来的问题是很难理解它的内部工作机制,以及很难根据自己的需求定制它(当你需要时)。我曾经写过的一些框架(例如MKStoreKit
,用于应用程序内购的 )总是易于使用,我认为MKNetworkKit 也应该是这样。对于 MKNetworkKit
,你所需要了解的就是暴露在两个类MKNetworkOperation 和 MKNetworkEngine 中的方法。MKNetworkOperation
就好比ASIHttpRequest类。它是一个NSOperation 子类,封装了你的 request 和 response
类。对于每个网络操作,你需要创建一个MKNetworkOperation 。

MKNetworkEngine 是一个伪单例类,管理程序中的网络队列。它是伪单例的,也就是说,对于简单请求,你可以直接用MKNetworkEngine
中的方法。要进行深度的定制,你应该进行子类化。每个 MKNetworkEngine 子类有它自己的Reachability
对象,用于通知它来自服务器的reachability 通知。对于不同的 REST 服务器,你可以考虑创建单独的 MKNetworkEngine子类。

它是伪单例,它的子类的每个请求都共用唯一的一个队列。你可以在应用程序委托中retain 这个 MKNetworkEngine ,就像CoreData 的
managedObjectContext 类一样。在使用MKNetworkKit 时,创建一个 MKNetworkEngine
子类将你的网络请求进行逻辑上的分组。例如,将所有关于 Yahoo 的方法放在一个类,所有 Facebook 有关的方法放进另一个类。来看 3
个实际使用的例子。

例1:

创建一个  “YahooEngine” 从 Yahoo 财经服务器抓取货币汇率。

步骤 1:创建YahooEngine 类继承于MKNetworkEngine。MKNetworkEngine
使用主机名和指定的头(如果有的话)进行初始化。头信息可以是nil。如果你是在自己的 REST 服务器上,你可以考虑加一个客户端 app
的版本或者其他信息(比如客户端的标识)。





NSMutableDictionary *headerFields = [NSMutableDictionary dictionary];     [headerFields
setValue:@"iOS"forKey:@"x-client-identifier"];

self.engine = [[YahooEngine
alloc] initWithHostName:@"download.finance.yahoo.com"                       
customHeaderFields:headerFields];

注意,yahoo 并不识别你在头中发送x-client-identifier 给它,这个示例仅仅是演示这个特性而

由于使用了 ARC 代码,作为开发者你需要拥有(强引用)Engine对象。

一旦你创建了一个 MKNetworkEngine子类, Reachability
即自动实现。当你的服务器由于某些情况挂了,主机名不可访问,你的请求会自动被冻结。关于“冻结”,请参考后面的“冻结操作”小节。

步骤 2:设计Engine 类 (关注分离)

现在,开始编写 Yahoo Engine 中的方法,以抓取汇率。这些方法将在ViewController 中被调用。良好的设计体验是确保不要将
engine 类中的 URL/HTTPHeaders 暴露给调用者。你的视图不应该知道URL 或者相关的参数。也就是,只需要向 engine
方法传递货币种类和货币单位就可以了。方法的返回值可能是 double,即汇率,以及获取汇率的时间。由于是异步操作,你应当在块中返回这些值。例如:




-(MKNetworkOperation*) currencyRateFor:(NSString*) sourceCurrency

inCurrency:(NSString*) targetCurrency

onCompletion:(CurrencyResponseBlock) completion

onError:(ErrorBlock) error;

在父类 MKNetworkEngine 中,定义了3 个块类型:




typedef void (^ProgressBlock)(double progress);

typedef void (^ResponseBlock)(MKNetworkOperation* operation);

typedef void (^ErrorBlock)(NSError* error);

在 YahooEngine中,我们使用了一个新的块类型:CurrencyResponseBlock,用以返回汇率。其定义如下:




typedef void (^CurrencyResponseBlock)(double rate);

在其他正式的 app 中,你应该定义自己的块类似于CurrencyResponseBlock ,用以向 ViewController
返回数据。

步骤 3:处理数据
处理数据,包括将从服务器抓来的数据(例如
JSON/XML/plists)进行数据类型转换。这应当在 Engine 中完成。注意,不要在控制器中完成。你的 Engine
应当将数据以适当的模型对象或模型对象的数组返回。在engine 中转换 JSON/XML 为模型——注意,适当保持关注分离,view controller
不应当知道任何用于访问 JSON 节点的 key。这种思想主导了engine
的设计。许多网络框架并不强制要求你服从关注分离,我们这样做,是因为我们为你考虑到了。

步骤 4:实现方法
现在,我们来讨论方法实现细节。要从 Yahoo 获得汇率信息,最简单的是发起一个 GET
请求。下列宏用一对指定的货币格式化 URL 字串:

We will now discuss the implementationdetails of the method that calculates
your currency exchange.

Getting currency information from Yahoo,is as simple as making a GET
request.
I wrote a macro to format this URL for a given currency pair.




#define YAHOO_URL(__C1__, __C2__) [NSString
stringWithFormat:@"d/quotes.csv?e=.csv&amp;f=sl1d1t1&amp;s=%@%@=X",
__C1__, __C2__]

按如下顺序编写 engine类方法:

  1. 根据参数准备 URL

  2. 创建一个 MKNetworkOperation 对象

  3. 设置方法参数

  4. 设置 operation 的 completion 块和 error 块(在 completation 块中处理 response
    并转换为模型)

  5. 可选地,添加一个 progress 块(或者在 view controller 中做这个)

  6. 如果 operation 是下载,设置下载流(通常是文件)。这步也是可选的

  7. 当 operation 完成,处理结果并调用方法块,并将数据返回给调用者。

示例代码如下:

MKNetworkOperation *op = [selfoperationWithPath: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;

上述代码格式化 URL 并创建了 MKNetworkOperation。设置完 completion 和 error 块之后,将 operation
加入到队列(通过父类的 enqueueOperation 方法),然后返回一个 operation 的引用。因此,如果你在 viewDidAppear
中调用这个方法,则在 viewWillDisappear 方法中取消operation。取消 operation 将释放 operation 以便执行
queue 中用于其他view 的 operation(牢记,在移动网络中只有2 个 operation 能被同时进行,当 operation
不再需要时取消它们能提升 app 的性能和速度)。

在 viewcontroller 中也可以添加一个 progress 块用以刷新UI。例如:




[self.uploadOperation
onUploadProgressChanged:^(double progress) {

DLog(@"%.2f",
progress*100.0);

self.uploadProgessBar.progress = progress;   
 }];

MKNetworkEngine 也有一个只用 URL 创建 operation 的有用方法。因此第1行代码也可以写成:




MKNetworkOperation *op = [self
operationWithPath:YAHOO_URL(sourceCurrency,
targetCurrency)];

注意,请求的 URL将自动添加上主机名(在 engine 实例化时指定的)。

像这样的实用方法 MKNetworkEngine还有许多,你可以查看头文件。

例2:

上传图片到服务器 (例如 TwitPic)。
现在让我们看一个上传图片到服务器的例子。要上传图片,显然要 operation 能编码
multi-part 表单数据。 MKNetworkKit 使用类似 ASIHttpRequest
的方式。
你可以非常简单地通过MKNetworkOperation 的 addFile:forKey:方法将一个文件作为请求中的 multi-part
表单数据提交。

MKNetworkOperation 也有一个方法,可以将图片以 NSData 的方式提交。即
addData:forKey: 方法,它可以将图片以NSData 的方法上传到服务器。 (例如直接从相机中捕获的图片).

例3:

下载文件到本地目录 (缓存)
使用MKNetworkKit 从服务器下载文件并保存到 iPhone 的本地目录非常简单。

只需要设置 MKNetworkOperation的 outputStream 。




[operation
setDownloadStream:[NSOutputStream        
outputStreamToFileAtPath:@"/Users/mugunth/Desktop/DownloadedFile.pdf"                      
  append:YES]];

你可以设置多个 outputStream 到一个
operation,将同一文件保存到几个地方(例如其中一个是你的缓存目录,另一个用做你的工作目录)。

例4:

缓存图片的缩略图

对于下载图片,你可能需要提供一个绝对 URL 地址而不是一个路径。
MKNetworkEngine
的operationWithURLString:params:httpMethod: 方法根据绝对 URL地址来创建网络线程。

MKNetworkEngine 相当聪明。它会将同一个 URL 的多次 GET 请求合并成一个,当 operation
完成时它会通知所有的块。这显著提升了抓取图片 URL 以渲染缩略图的速度.

子类化 MKNetworkEngine然后覆盖图片的缓存目录及缓存的大小。如果你不想定制这二者,你可以直接调用
MKNetworkEngine中的方法来下载图片。这是我极力推荐的。

缓存operation

MKNetworkKit 默认会缓存所有请求。你所需要的仅仅是在你自己的 engine 中打开它。当执行一个 GET 请求时,如果上次的 response
已缓存,相应的 completion 块将用缓存的response 进行调用(瞬间)。要想知道 response 是否缓存,可以调用
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);

}];

冻结operation

MKNetworkKit 的一个最有趣的特性是它内置的冻结 operation 特性。你只需要设置 operation 的 freeesable
属性就可以。几乎什么也不用做!




[op
setFreezable:YES];

冻结是指 operation 在网络被断开时自动序列化并在网络恢复后自动执行。例如当你离线时也能够进行收藏tweet 的操作,然后在你再次上线时
operation 自动恢复执行。

在应用程序进入后台时,冻结的 operation 也会被持久化到磁盘。然后在应用程序回到前台后自动恢复执行。

MKNetworkOperation 中的有用方法

如下所示,MKNetworkOperation 公开了一些有用的方法,你可从中获取各种格式的 response 数据:

  1. responseData

  2. responseString

  3. responseJSON (Only on iOS 5)

  4. responseImage

  5. responseXML

  6. error

当 operation 执行完时,这些方法被用于获取响应数据。如果格式不正确,方法会返回nil。例如,响应的数据明明是一个 HTML 格式,你用
responseImage 方法只会得到 nil。只有 responseData 能保证无论什么格式都返回正确,而其他方法你必须确保和相应的repsone
类型匹配。

有用的宏

DLog 和 ALog 宏被无耻地从 Stackoverflow 剽窃来了,我找不到源作者。如果是你写的,请告诉我。

关于GCD 的一点说明

因为网络线程有可能会能被停止或优先处理,我果断放弃了 GCD——GCD 的效率是比NSOperation
高,但它做不到这一点。我建议在你的网络线程中也不要使用基于 GCD 的队列。

源码百度云

转载地址:http://blog.csdn.net/kmyhy/article/details/12276287

时间: 2024-08-25 15:07:36

MKNetWorkKit(转载)的相关文章

MKNetworkKit 使用

1.MKNetworkKit 框架添加 1. 添加pch 文件 a. command + N  → 选择 Other → PCH File b.点击项目名 → 点击 TARGETS → Build Settings → 搜索 language → Prefix Header 双击 → 添加 $(SRCROOT)/项目名/pch文件名 c.在pch 文件中添加 #ifdef __OBJC__ #import <Foundation/Foundation.h> #import "MKNe

【转载】C++拷贝构造函数(深拷贝,浅拷贝)

对于普通类型的对象来说,它们之间的复制是很简单的,例如:int a=88;int b=a; 而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量.下面看一个类对象拷贝的简单例子. #include <iostream>using namespace std;class CExample {private:     int a;public:     CExample(int b)     { a=b;}     void Show ()     {        cout<

门控时钟-理论分析 ---- 转载

转载自:http://www.chipsbank.com/news_detail/newsId=123.html 门控的基本要求: 1. 所需要的沿(对于正沿触发的寄存器是正沿,对于负沿触发的寄存器是负沿)不增加,不减少: 1. 不会产生毛刺: 1. 使用后功耗要能够降低: 1. 最好面积还会减小. 1. 上升沿触发的门控时钟的结构研究:应用与上升沿触发的寄存器的门控. 1. 直接与门结构: 1. 高电平使能Latch + 与门结构: 1. 低电平使能Latch + 与门结构: 1. 波形研究:

浅谈Java中的equals和==(转载)

在初学Java时,可能会经常碰到下面的代码: 1 String str1 = new String("hello"); 2 String str2 = new String("hello"); 3 4 System.out.println(str1==str2); 5 System.out.println(str1.equals(str2)); 为什么第4行和第5行的输出结果不一样?==和equals方法之间的区别是什么?如果在初学Java的时候这个问题不弄清楚,就

JVM学习(2)——技术文章里常说的堆,栈,堆栈到底是什么,从os的角度总结--转载http://www.cnblogs.com/kubixuesheng/p/5202561.html

转载自---http://www.cnblogs.com/kubixuesheng/p/5202561.html 俗话说,自己写的代码,6个月后也是别人的代码--复习!复习!复习!涉及到的知识点总结如下: 堆栈是栈 JVM栈和本地方法栈划分 Java中的堆,栈和c/c++中的堆,栈 数据结构层面的堆,栈 os层面的堆,栈 JVM的堆,栈和os如何对应 为啥方法的调用需要栈 属于月经问题了,正好碰上有人问我这类比较基础的知识,无奈我自觉回答不是有效果,现在深入浅出的总结下: 前一篇文章总结了:JV

GitHub超详细图文攻略 - Git客户端下载安装 GitHub提交修改源码工作流程 Git分支 标签 过滤 Git版本工作流(转载)

最近听同事说他都在使用GitHub,GitHub是程序员的社区,在里面可以学到很多书上学不到的东西,所以最近在准备入手这方面的知识去尝试学习,正好碰到这么详细完整的文章,就转载了,希望对自己和大家有帮助. GitHub操作总结 : 总结看不明白就看下面的详细讲解. GitHub操作流程 : 第一次提交 : 方案一 : 本地创建项目根目录, 然后与远程GitHub关联, 之后的操作一样; -- 初始化Git仓库 :git init ; -- 提交改变到缓存 :git commit -m 'desc

2.EasyUI学习总结(二)——easyloader分析与使用(转载)

本文转载自:http://www.cnblogs.com/haogj/archive/2013/04/22/3036685.html 使用脚本库总要加载一大堆的样式表和脚本文件,在easyui 中,除了可以使用通常的方式加载之外,还提供了使用 easyloader 加载的方式.这个组件主要是为了按需加载组件而诞生.什么情况下使用它呢? 你觉得一次性导入 easyui 的核心 min js 和 css 太大 你只用到 easyui 的其中几个组件 你想使用其中的一个组件,但是你又不知道这个组件依赖

Data guard概念篇一(转载)

本文转载至以下链接,感谢作者分享! http://tech.it168.com/db/2008-02-14/200802141545840_1.shtml 一.Data Guard配置(Data Guard Configurations) Data Guard是一个集合,由一个primary数据库(生产数据库)及一个或多个standby数据库(最多9个)组成.组成Data Guard的数据库通过Oracle Net连接,并且有可能分布于不同地域.只要各库之间可以相互通信,它们的物理位置并没有什么

【转载】GBDT(MART) 迭代决策树入门教程 | 简介

      转载地址:http://blog.csdn.net/w28971023/article/details/8240756        GBDT(Gradient Boosting Decision Tree) 又叫 MART(Multiple Additive Regression Tree),是一种迭代的决策树算法,该算法由多棵决策树组成,所有树的结论累加起来做最终答案.它在被提出之初就和SVM一起被认为是泛化能力(generalization)较强的算法.近些年更因为被用于搜索排