This article is available in Serbo-Croatian,  JapaneseGerman and French.

(Translations in Serbo-Croatian by Jovana Milutinovich, Japanese by @noradaiko, German by Jonas Pencke (@jonaspencke) and French by Anna Chekovsky)

Translations in other languages are welcome!

 

How awesome would it be if a networking framework automatically takes care of caching responses for you?

How awesome would it be if a networking framework automatically remembers your operations when your client is offline?

You favorite a tweet or mark a feed as read when you are offline and the Networking Framework performs all these operations when the device comes back online, all with no extra coding effort from you. Introducing MKNetworkKit.

 

What is MKNetworkKit?

MKNetworkKit is a networking framework written in Objective-C that is seamless, block based, ARC ready and easy to use.
MKNetworkKit is inspired by the other two popular networking frameworks, ASIHTTPRequest and AFNetworking. Marrying the feature set from both, MKNetworkKit throws in a bunch of new features. In addition to this, MKNetworkKit mandates you to write slightly more code than the other frameworks at the expense of code clarity. With MKNetworkKit, it’s hard to write ugly networking code.

Features

Super light-weight
超级轻量级

The complete kit is just 2 major classes and some category methods. This means, adopting MKNetworkKit should be super easy.

完整的工具包只有两个主要的类和一些category方法。这意味着MKNetworkKit将是超级容易使用的。


Single Shared Queue for your entire application.
一个共享队列为你的整个应用提供服务; 

Apps that depend heavily on Internet connectivity should optimize the number of concurrent network operations. Unfortunately, there is no networking framework that does this correctly. Let me give you an example of what can go wrong if you don’t optimize/control the number of concurrent network operations in your app.

重度依赖网络连接的应用应该优化当前连接操作数,不幸地,没有网络框架能正确地做到这一点。让我给你一个例子,当你没有在应用中优化或控制当前网络连接数时,将会出现怎样的错误。

Let’s assume that you are uploading a bunch of photos (think Color or Batch) to your server. Most mobile networks (3G) don’t allow more than two concurrent HTTP connections from a given IP address. That is, from your device, you cannot open more than two concurrent HTTP connections on a 3G network. Edge is even worse. You can’t, in most cases, open more than one connection. This limit is considerably high (six) on a traditional home broadband (Wifi). However, since your iDevice is not always connected to Wifi, you should be prepared for throttled/restricted network connectivity. On any normal case, the iDevice is mostly connected to a 3G network, which means, you are restricted to upload only two photos in parallel. Now, it is not the slow upload speed that hurts. The real problem arises when you open a view that loads thumbnails of photos (say on a different view) while this uploading operations are running in the background. When you don’t properly control the queue size across the app, your thumbnail loading operations will just timeout which is not really the right way to do it. The right way to do this is to prioritize your thumbnail loading operation or wait till the upload is complete and the load thumbnails. This requires you to have a single queue across the entire app. MKNetworkKit ensures this automatically by using a single shared queue for every instance of it. While MKNetworkKit is not a singleton by itself, the shared queue is.

让我们假设你上传一组图片(如颜色或批量)到你的服务器。多数移动网络(3G)不允许多于2个并发的来自相同IP地址的http连接。因此你不能在你的设备中在3G网络下打开2个以上的并发连接。Edge网络更差,在很多情况下你不能打开一个以上的连接。这种限制比一个传统的家庭宽带(wifi)的限制高得多。然而,当你的智能设备不是一直连接着wifi,你应该为节省流量或限制网络连接作准备。在一般情况下,这些智能设备一般会连接3G网络,这意味着,你被限制并发上传2个图像。现在,它没有着减慢上传速度。真正的问题是当你打开一个视图加载图片缩略图(在不同的视图)而 这个上传操作在后台运行。当你没有在整个应用中适当控制连接队列大小,你的加载缩略图操作将超时,这不是真正正确的处理方法。正确的方法是确定缩略图加载操作的优先级或等待上传完成后再加载缩略图。这需要你有一个单独队列处理整个应用的连接。KMNetworkKit为每一个连接实例使用一个单独的共享队列来保证以上的情况。虽然MKNetworkKit本身不是一个单例,但共享队列是一个单例。



Showing the Network Activity Indicator correctly
正确显示网络活动指示器

While there are many third party classes that uses “incrementing” and “decrementing” the number of network calls and using that to show the network activity indicator, MKNetworkKit backs on the single shared queue principle and shows the activity indicator automatically when there is an operation running in the shared queue by observing (KVO) the operationCount property. As a developer, you normally don’t have to worry about setting the network activity indicator manually, ever again.

虽然现在有很多第三方的类使用“increamenting”和”decrementing”网络请求数和使用这去显示网络活动指示器,当一个操作通过监视operationCount属性在共享队列里运行时,MKNetworkKit 依靠单独共享队列规则显示活跃指示器作为一个开发者,你通常没必要提心手动地设置网络活跃指示器。

if (object == _sharedNetworkQueue && [keyPath isEqualToString:@"operationCount"]) {
 
        [UIApplication sharedApplication].networkActivityIndicatorVisible =
        ([_sharedNetworkQueue.operations count] > 0);
    }



Auto queue sizing
自动队列大小

Continuing the previous discussion, I told that most mobile networks don’t allow more than two concurrent connections. So your queue size should be set to two, when the current network connectivity is 3G. MKNetworkKit automatically handles this for you. When the network drops to 3G/EDGE/GPRS, it changes the number of concurrent operations that can be performed to 2. This is automatically changed back to 6 when the device connects back to a Wifi network. With this technique in place, you will see a huge performance benefit when you are loading thumbnails (or multiple similar small requests) for a photo library from a remote server over 3G.

继续前面的讨论,我说过,多数移动网络不允许多于2个并发连接。所以当前前网络连接为3G时,你的队列大小应设置为2。

MKNetworkKit 自动为你处理。当网络为3G/EDGE/GPRS,它改变当前操作数为2 .当设备连接到wifi热点时,连接数自动改变为6。使用这种技术,你会看到,当你使用3G从一个远程服务器加载缩略图(或者多个相似的小请求),会得到非常大的好处; 

Auto caching
自动缓存

MKNetworkKit can automatically cache all your “GET” requests. When you make the same request again, MKNetworkKit calls your completion handler with the cached version of the response (if it’s available) almost immediately. It also makes a call to the remote server again. After the server data is fetched, your completion handler is called again with the new response data. This means, you don’t have to handle caching manually on your side. All you need to do is call one method,

MKNetworkKit 能自动缓存所有你的GET请求。当你发出同样的请求时,MKNetworkKit直接调用缓存了响应数据的完整的handler。同样它会发送一个请求到远程服务器。当获得服务器响应数据,你的completion handler会再次调起,处理新的响应数据。这意味着,你不需要手动处理缓存。你需要做的只是调起一个方法:


[[MKNetworkEngine sharedEngine] useCache];


Optionally, you can override methods in your MKNetworkEngine subclass to customize your cache directory and in-memory cache cost.

你能在MKNetworkEngine 子类中重写方法,自定义你的缓存目录和内存缓存花费; 


Operation freezing
冻结操作

With MKNetworkKit, you have the ability to freeze your network operations. When you freeze an operation, in case of network connectivity losses, they will be serialized automatically and performed once the device comes back online. Think of “drafts” in your twitter client.

通过MKNetworkKit,你能冻结你的网络操作。当网络连接丢失时冻结一个操作,它们将在设备再次在线时自动继续冻结前的操作;

When you post a tweet, mark that network call as freezable and MKNetworkKit automatically takes care of freezing and restoring these requests for you! So the tweets get sent later without you writing a single line of additional code. You can use this for other operations like favoring a tweet or sharing a post from your Google reader client, adding a link to Instapaper and similar operations.

当你发一个tweet信息时,标记网络是可冻结的,则MKNetworkKit将自动为你处理冻结和恢复这些请求;所以这条tweets会在稍后自动发送 ,而你不用单独写一行额外的代码。

你能为其他像从你的Google阅读客户端收藏或分享一个贴子、添加一个链接到Instapaper等类似的操作使用MKNetworkKit这个特性; 


Performs exactly one operation for similar requests
为类似的请求准确执行一个操作

When you load thumbnails (for a twitter stream), you might end up creating a new request for every avatar image. But in reality, you only need as many requests as there are unique URLs. With MKNetworkKit, every GET request you queue gets executed exactly once. MKNetworkKit is intelligent enough not to cache “POST” http requests.

当你加载缩略图(为一个twitter流),你不用再为每一个头像图片创建一个新的请求。但在现实中,你只需要一个唯一的URLs。使用MKNetworkKit,队列中每一个GET请求将准确执行一次。MKNetworkKit 足够智能地不缓存POST http请求; 

Image Caching
图片缓存

MKNetworkKit can be seamlessly used for caching thumbnail images. By overriding a few methods, you can set how many images should be held in the in-memory cache and where in the Caches directory it should be saved. Overriding these methods are completely optional.

MKNetworkKit 能完美地缓存缩略图。通过重写一些方法,你能设置在内存中缓存多少图片、在哪个目录保存缓存数据。重写的方法完全是可选的; 

Performance
执行

One word. SPEED. MKNetworkKit caching is seamless. It works like NSCache, except that, when there is a memory warning, the in-memory cache is written to the Caches directory.

一个字:“速度”。MKNetworkKit 缓存是天衣无逢的。它像NSCache一样工作,当内存告警时,内存缓存会写到缓存目录里; 

Full support for Objective-C ARC
为OBjective-C ARC提供全面支持

You normally choose a new networking framework for new projects. MKNetworkKit is not meant for replacing your existing framework (though you can, it’s quite a tedious job). On new projects, you will almost and always want to enable ARC and as on date of writing this, MKNetworkKit is probably the only networking framework that is fully ARC ready. ARC based memory management is usually an order of magnitude faster than non-ARC based memory management code.

你一般会为一个新项目选择一个新的网络框架。MKNetworkKit 并不意味着要替换你的已有框架(虽然你可以,但它是很无聊的工作)。一个新的项目,你总是或一直想使用ARC,MKNetworkKit 可能是唯一一个完全为ARC准备的网络框架。基于ARC内存管理通常比非基于ARC内存管理的代码快很多; 


How to use

如何使用

Ok, Enough self-praises. Let us now see how to use the framework.

OK,臭美够了,让我们现在看看怎样来使用这个框架; 

Adding the MKNetworkKit

添加MKNetworkKit
  1. Drag the MKNetworkKit directory to your project.
  2. Add the CFNetwork.Framework, SystemConfiguration.framework, Security.framework and ImageIO.Framework.
  3. Include MKNetworkKit.h to your PCH file
  4. Delete NSAlert+MKNetworkKitAdditions.h file if you are building for iOS.
  5. Delete UIAlertView+MKNetworkKitAdditions.h file if you are building for Mac.

You are done. Just 5 core files and there you go. A powerful networking kit.

1.把MKNetworkKit目录拖到你的项目中。

2.添加CFNetwork.Framework,SystemConfiguration.framework,Security.framework 和imageIO.Framework.

3.包含MKNetworkKit.h到你的头文件; 

4.如果你是开发IOS应用,则删 除NSAlert+MKNetworkKitAdditions.h文件; 

5.如果你是开发MAC应用,则删除UIAlertView+MKNetworkKitAdditions.h文件; 


Classes in MKNetworkKit

MKNetworkKit的类
  1. MKNetworkOperation
  2. MKNetworkEngine
  3. Miscellaneous helper classes (Apple’s Reachability) and categories 辅助类和扩展类目; 

I believe in simplicity. Apple has done the heavy lifting of writing the actual networking code. What a third-party networking framework should provide is an elegant queue based networking with optional caching. I believe that, any third party framework should have under 10 classes (whether it’s networking or UIKit replacement or whatever). More than that is a bloat. Three 20 library is an example of bloat and so is ShareKit. May be it’s good. But it still huge and bloated. ASIHttpRequest or AFNetworking are lean and lightweight, unlike RESTKit. JSONKit is lightweight unlike TouchJSON (or any of the TouchCode libraries). May be it’s just me, but I just can’t take it when more than a third of source code lines in my app comes from a third party library.

我天真的相信,苹果已经编写实际的网络代码这样的艰巨任务。第三方网络框架应该提供一个基于优雅队列的可选的缓存的网络。

我相信,任何第三方框加应该少于10个类(如果它是网络或者UIKit代替替者或其他。)多过10个类都是臃肿的。ShareKit就是一个臃肿的例子,虽然它是不错的,但是巨大和臃肿的。ASIHttpRequest或者AFNetworking是较小的轻量级的,不像RESTKit.  JSONKit是轻量级的不像TouchJSON(或者任何TouchCode库)。或者只有我,但我只是不能接受在我的应用中多于3行来自第三方库的源代码; 

The problem with a huge framework is the difficulty in understanding the internal working and the ability to customize it to suit your needs (in case you need to). My frameworks (MKStoreKit for adding In App Purchases to your app) have always been super easy to use and I believe MKNetworkKit would also be the same. For using MKNetworkKit, all you need to know are the methods exposed by the two classes MKNetworkOperation and MKNetworkEngine. MKNetworkOperation is similar to the ASIHttpRequest class. It is a subclass of NSOperation and it wraps your request and response classes. You create a MKNetworkOperation for every network operation you need in your application.

巨大的框架带来的问题是,难于懂得内部的工作机制和难于客户化从而适配合你的需要(在你必须的情况下)。我的框架(在应用中添加内购MKStoreKit )一直是超级易于使用,我相信MKNetworkKit同样易于使用。

使用MKNetworkKit,你只需弄懂MKNetworkOperation 和MKNetworkEngine两个类提供的方法;MKNetworkOperation是一个跟ASIHttpRequest相似的类。它是NSOperation是子类,它封装你的请求和响应类。你在应用中为每一个网络操作创建一个MKNetworkOperation;


MKNetworkEngine is a pseudo-singleton class that manages the network queue in your application. It’s a pseudo-singleton, in the sense, for simple requests, you should use MKNetworkEngine methods directly. For more powerful customization, you should subclass it. Every MKNetworkEngine subclass has its own Reachability object that notifies it of server reachability notifications. You should consider creating a subclass of MKNetworkEngine for every unique REST server you use. It’s pseudo-singleton in the sense, every single request in any of it’s subclass goes through one and only one single queue.

MKNetworkEngin e是一个伪单例类,管理你应用中的网络队列。它是一个伪单例,在这个情景中,一个简单的请求,你应该直接使用MKNetworkEngine的方法。当然,你可以实现它的子类来实现更强大的客户化。每一个MKNetworkEngine的了类有一个Reachability对象,用于通知它是否服务器可以接通。你应该为每一个唯一的REST服务创建一个子MKNetworkEngine类。它作为一个伪单例,因此它的每一个子类的请求都在同一个队列里; 


You can retain instances of your MKNetworkEngine in your application delegate just like CoreData managedObjectContext class. When you use MKNetworkKit, you create an MKNetworkEngine sub class to logically group your network calls. That is, all Yahoo related methods go under one single class and all Facebook related methods into another class. We will now look at three different examples of using this framework.

你能像CoreData managedObjectContext类一样在你的应用代理中保留你的MKNetworkEngine实例。当你使用MKNetworkKit,你应该创建一个MKNetworkEngine子类在逻辑层面组织你的网络请求。如,所有的Yahoo相关的方法在一个单独的类里、所有的Facebook相关的方法在另一个类里。我们现在将看到使用这个框架的3个不同的例子; 


Example 1:

Let’s now create a “YahooEngine” that pulls currency exchange rates from Yahoo finance.

让我们现在创建一个“YahooEngin”从Yahoo金融中拉取汇率;

Step 1: Create a YahooEngine class as a subclass of MKNetworkEngine. MKNetworkEngine init method takes hostname and custom headers (if any). The custom headers is optional and can be nil. If you are writing your own REST server (unlike this case), you might consider adding client app version and other misc data like client identifier.

步骤1:创建一个继承MKNetworkEngine的YahooEngine类。MKNetworkEngine初始化方法有两个参数:主机名和请求头。请求头是可选的,可以置为nil.如果你写你自己的REST服务器(不像这这个例子),你应该考虑添加客户端应用版本和其他misc数据,如客户端标识.

  NSMutableDictionary *headerFields = [NSMutableDictionary dictionary];
    [headerFields setValue:@"iOS" forKey:@"x-client-identifier"];
 
    self.engine = [[YahooEngine alloc] initWithHostName:@"download.finance.yahoo.com"
                       customHeaderFields:headerFields];


Note that, while yahoo doesn’t mandate you to send x-client-identifier in the header, the sample code shown above sends this just to illustrate this feature.

注意,yahoo并没有授权你在请求头发送 x-client-identifier,上像的例子只是描述这种应用;

Since the complete code is ARC, it’s up to you as a developer to own (strong reference) the Engine instance.

自整套代码是ARC后,开发者是否使用强引用来引用Engine实例,这完全取决于你自己。

When you create a MKNetworkEngine subclass, Reachability implementation is done automatically for you. That’s when your server goes down or due to some unforeseen circumstances, the hostname is not reachable, your requests will automatically be queued/frozen. For more information about freezing your operations, read the section Freezing Operations later in the page.

当你创建一个MKNetworkEngine子类,将自动为你实现Reachability.这样当你的服务器关闭或者出现不可预料的故障令到主机不能连接时,你的请求会自动排队和冻结。更多关于冻结网络操作的信息,请阅读本页后面关于冻结操作的部份; 

Step 2: Designing the Engine class (Separation of concerns)

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

Let’s now start write the methods in Yahoo Engine to fetch exchange rates. The engine methods will be called from your view controller. A good design practice is to ensure that your engine class doesn’t expose URL/HTTPHeaders to the calling class. Your view should not “know” about URL endpoints or the parameters needed. This means, parameters to methods in your Yahoo Engine should be the currencies and the number of currency units. The return value of this method could be a double value that is the exchange rate factor and may be the timestamp of the time it was fetched. Since operations are not performed synchronously, you should return these values on blocks. An example of this would be,

让我们开始在Yahoo Engine中写获取汇率的方法。engine方法将在你的视图控制器中调用; 一个好的设计实践是在你的engine类里不对外提供URL/HTTPHeaders的操作;你的视图应该”不知道“ URL端或者需要的参数。这意味着YahooEnginer的方法的参数应该是货币或者是货币的单位数。方法的返加值应该是一个双精度的汇率因子和可能是获取数据的时间戳。当操作不是同步执行时,你应该在blocks里返回这些值。例子如下:

-(MKNetworkOperation*) currencyRateFor:(NSString*) sourceCurrency
                   	    inCurrency:(NSString*) targetCurrency
			  onCompletion:(CurrencyResponseBlock) completion
        	               onError:(ErrorBlock) error;


MKNetworkEngine, the parent class defines three types of block methods as below.

MKNetworkEngine,父类定义了以下三种类型的block方法

typedef void (^ProgressBlock)(double progress);
typedef void (^ResponseBlock)(MKNetworkOperation* operation);
typedef void (^ErrorBlock)(NSError* error);


In our YahooEngine, we are using a new kind of block, CurrencyResponseBlock that returns the exchange rate. The definition looks like this.

在我们的YahooEngine里,我们使且新类型的bloack,CurrencyResponseBlock 返回汇率。定义如下:

typedef void (^CurrencyResponseBlock)(double rate);


In any normal application, you should be defining your own block methods similar to this CurrencyResponseBlock for sending data back to the view controllers.

在任何一般应用中,你应该定义你自己的block方法,像CurrncyResposeBlock一样,返回数据到视图控制器。

Step 3: Processing the data

步骤3:处理数据
Data processing, that is converting the data you fetch from your server, whether it’s JSON or XML or binary plists, should be done in your Engine. Again, relieve your controllers of doing this task. Your engine should send back data only in proper model objects or arrays of model objects (in case of lists). Convert your JSON/XML to models in the engine. Again, to ensure proper separation of concerns, your view controller should not “know” about the “keys” for accessing individual elements in your JSON.

数据处理,就是转换从服务器获取的数据,它可能是JSON、XML、或者是二进制plists,这些数据应该在Engine中处理。避免在控制器处理这些任务。你的engine应该只返回适当的数据模型对象或者模型对象的数组。在engine里把JSON/XML转换为模型。再次,为保证合适的关注分离,你的视图控制器应该不知道访问JSON里的独立元素的Keys;

That concludes the design of your Engine. Most networking framework doesn’t force you to follow this separation of concerns. We do, because we care for you :)

最后,很多网络框架不会强制你进行关注分离。但我们会强制,因为我们关心你;

Step 4: Method implementation

步骤4:方法实现
We will now discuss the implementation details of the method that calculates your currency exchange.

我们现在将讨论方法的实现细节,计算你的货币汇兑;

Getting currency information from Yahoo, is as simple as making a GET request.

从Yahoo获取货币信息,像发送一个GET请求那样简单。
I wrote a macro to format this URL for a given currency pair.

我写一个宏用于格式化一个含有货币对的URL。

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


Methods you write in your engine class should do the following in order.

  1. Prepare your URL from the parameters.   1.设置URL
  2. Create a MKNetworkOperation object for the request. 2.为请求创建MKNetworkOperation对象
  3. Set your method parameters.3.设置你方法里的参数
  4. Add completion and error handlers to the operation (The completion handler is the place to process your responses and convert them to Models.) 4.添加完成和出错处理操作。
  5. Optionally, add progress handlers to the operation. (Or do this on the view controller) 5可选,添加进度处理;
  6. If your operation is file download, set a download stream (normally a file) to it. This is again optional. 6.如果是下载文件,设置下载流(一般为文件)。这也是可选的。
  7. When the operation completes, process the result and invoke the block method to return this data to the calling method.  7,当操作完成,处理结果和引用块方法返回数据给调用言法。

This is illustrated in the following code

下面是实现代码

       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;

The above code formats the URL and creates a MKNetworkOperation. After setting the completion and error handlers it queues the operation by calling the super class’s enqueueOperation method and returns a reference to it. Your view controller should own this operation and cancel it when the view is popped out of the view controller hierarchy. So if you call the engine method in, say viewDidAppear, cancel the operation in viewWillDisappear. Canceling the operation will free up the queue for performing other operations in the subsequent view (Remember, only two operations can be performed in parallel on a mobile network. Canceling your operations when they are no longer needed goes a long way in ensuring performance and speed of your app).

上面的代码格式化一个URL和创建一个MKNetworkOperation.设置完成和错误处理后,它通过父类的enqueueOperation方法将请求放入队列中交返加一个它引用。你的视图控制器将拥有这个操作,当视图跳出视图控制器时取消它。所以如果你调用engine方法ViewDidAppear,应该在viewWillDisappear中取消它。取消操作将取消所有在后代视图中执行的队列(记信,在移动网络里只能并行两个网络请求。当你不再需要这些请求和优代你的应用速度时取消这此请求。)

You view controller can also (optionally) add progress handlers and update the user interface. This is illustrated below.

你的视图控制器同样(可选)添加进度处理和更新你的用户界面。代码如下:

   [self.uploadOperation onUploadProgressChanged:^(double progress) {
 
        DLog(@"%.2f", progress*100.0);
        self.uploadProgessBar.progress = progress;
    }];


MKNetworkEngine also has convenience methods to create a operation with just a URL. So the first line of code can also be written as

MKNetworkEngine同样有一个便捷的方法通过URL来创建请求。所以第一行代码你可以这样写:

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

Do note here that request URLs are automatically prefixed with the hostname you provided while initializing your engine class.

请记住,请求的URL会自动添加主机名,这个主机名在你初始化engine时设置的;

Creating a POST, DELETE or PUT method is as easy as changing the httpMethod parameter. MKNetworkEngine has more convenience methods like this. Read the header file for more.

创建一个POST,DELETE或者PUT方法很简单,只需改变HttpMethod的参数。MKNetworkEngine有很多这样便捷的方法。阅读头文件获取更多信息。

Example 2:

例子2:

Uploading an image to a server (TwitPic for instance).

上传图片到服务器
Now let us go through an example of how to upload an image to a server. Uploading an image obviously requires the operation to be encoded as a multi-part form data. MKNetworkKit follows a pattern similar to ASIHttpRequest.

现在让我面通过一个例子来展示如何上传图片到服务器。上传图片显然要把请求头设置为multi-part类型的请求。MKNetworkKit的方式类似ASIHttpRequest.
You call a method addFile:forKey: in MKNetworkOperation to “attach” a file as a multi-part form data to your request. It’s that easy.

你在MKNetworkOperation中调用方法 addFile:forKey:会以multi-part格式添加文件到请求中。非常简单。
MKNetworkOperation also has a convenience method to add a image from a NSData pointer. That’s you can call addData:forKey: method to upload a image to your server directly from NSData pointer. (Think of uploading a picture from camera directly).

MKNetworkOperation同样有一些便捷的方法以NSData指针形式添加图片。你可以调用addData:forKey:方法直接通过NSData指针上传图片到服务器。(如直接从照相机上传图片)。

Example 3:

例子3:

Downloading files to a local directory (Caching)

下载文件到本地目录(缓存)
Downloading a file from a remote server and saving it to a location on users’ iPhone is super easy with MKNetworkKit.

使用MKNetworkKit从远程服服器下载文件并保存到你的iPhone里是超级容易的事。
Just set the outputStream of MKNetworkOperation and you are set.

只需设置MKNetworkOperation的outputStream:

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

You can set multiple output streams to a single operation to save the same file to multiple locations (Say one to your cache directory and one to your working directory)

你可以在一个请求中设置文个输出流来保存相同的文件到不同的目录(如一个保存在缓存目录一个保存在工作)。

Example 4:

例子4:

Image Thumbnail caching

缓存缩略图
For downloading images, you might probably need to provide an absolute URL rather than a path. MKNetworkEngine has a convenience method for this. Just call operationWithURLString:params:httpMethod: to create a network operation with an absolute URL.

下载图片时,你很可能需要提供一个绝对URL.MKNetworkEngine有一个便捷的方法。operationWithURLString:params:httpMethod:方法使用绝对URL创建网络请求; 
MKNetworkEngine is intelligent. It coalesces multiple GET calls to the same URL into one and notifies all the blocks when that one operation completes. This drastically improves the speed of fetching your image URLs for populating thumbnails.

MKNetworkEngine是智能的。它合并同样URL的GET请求并当请求完成时通知所有的blocks。它狠狠地提高了获取图片缩略图的速度;

Subclass MKNetworkEngine and override image cache directory and cache cost. If you don’t want to customize these two, you can directly call MKNetworkEngine methods to download images for you. I would actually recommend you to do that.

如果你不想子类化MKNetworkEngine和重写图片缓存目录和缓存使用,你可以直接调用MKNetworkEngine方法来下载图片。

Caching operations

缓存操作

MKNetworkKit caches all requests by default. All you need to do is to turn on caching for your Engine. When a GET request is performed, if the response was previously cached, your completion handler is called with the cached response almost immediately. To know whether the response is cached, use the isCachedResponse method. This is illustrated below.

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);
     }];


Freezing operations

冻结操作:

Arguably, the most interesting feature of MKNetworkKit is built in ability to freeze operations. All you need to do is set your operation as freezable. Almost zero effort!

MKNetworkKit最有趣的特性是可以冻结操作。你只需把你的请求设置为可冻结的。

[op setFreezable:YES];

Freezable operations are automatically serialized when the network goes down and executed when connectivity is restored. Think of having the ability to favorite a tweet while you are offline and the operation is performed when you are online later.

可冻结的请求当网络掉线时会自动冻结,当网络恢复时自动执行; 可以想像,你在离线状态下收藏了一条微信信息,而在你在线时自动执行收藏请求;
Frozen operations are also persisted to disk  the app enters background. They will be automatically performed when the app is resumes later.

冻结请求可以在应用进入后台时保持冻结,当应用恢复时会自动执行冻结了的请求;

Convenience methods in MKNetworkOperation

MKNetworkOperation的便捷方法

MKNetworkOperation exposes convenience methods like the following to get the format your response data.

MKNeworkOperation有如下的便捷方法用于格式化响应数据:

  1. responseData
  2. responseString
  3. responseJSON (Only on iOS 5)
  4. responseImage
  5. responseXML
  6. error

They come handy when accessing the response after your network operation completes. When the format is wrong, these methods return nil. For example, trying to access responseImage when the actual response is a HTML response will return nil. The only method that is guaranteed to return the correct, expected response is responseData. Use the other methods if you are sure of the response type.

当请求完成时访问响应数据时它们非常有用。当格式化错误时,返回nil.例如,当通过responseImage访问HTML时会返回nil.只有responseData方法任何情况都会返回正确。如果你确定响应类型,请使用其他方法。

Convenience macros

便捷的宏

The macros, DLog and ALog were stolen unabashedly from Stackoverflow and I couldn’t again find the source. If you wrote that, let me know.


A note on GCD

I purposefully didn’t use GCD because, network operations need to be stopped and prioritized at will. GCD, while more efficient than NSOperationQueue, cannot do this. I would recommend not to use GCD based queues for your network operations.

Documentation

The header files are commented and I’m trying out headerdoc from Apple. Meanwhile, you can use/play around (read: Fork) with the code.

Source Code

The source code for MKNetworkKit along with a demo application is available on Github.
MKNetworkKit on Github

Feature requests

Please don’t email me feature requests. The best way is to create an issue on Github.

Licensing

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 


Mugunth