MKNetworkKit

沒有認識MK以前,即使ASI已經再也不更新,也沒有啓用ASI。由於ASI對於網絡的處理更偏向於底層,適合針對各類情形的擴展。html

可是,今天我要開始使用 MKNetworkKit了,項目在github上,使用說明在做者的主頁上。ios

之因此推薦這個項目,除了它列舉的功能以外,更重要的在於它徹底是MVC的設計思想。git

相對於代碼,背後的設計思想更讓人值得回味。github

另外,已經有一篇中文翻譯(以下),各位趕忙使用吧~web

轉自: http://t.cn/zQJWX2Sobjective-c

iOS Framework: Introducing MKNetworkKit (MKNetworkKit介紹,入門,翻譯)

這片文章也有塞爾維亞-克羅地亞語(由Jovana Milutinovich翻譯)和日語(由@noradaiko翻譯)json

若是有個一個網絡庫可以自動的爲你處理cache該有多好啊。數組

若是有一個網絡庫可以在設備離線的時候自動的記住用戶的操做該有多酷啊。緩存

當你離線的時候,你喜歡了一條微博或者把一條新聞標記爲已讀,而後網絡庫會在設備連網後自動執行這些操做,而且還不用寫一行多餘的代碼。下面咱們就介紹MKNetworkKit能夠作到這些。服務器

 

什麼是 MKNetworkKit?

MKNetworkKit 是一個用objective-c寫的網絡庫,具備無縫鏈接,基於block,ARC支持以及易用等特色。

MKNetworkKit的靈感來自於其餘兩個流行的網絡庫:ASIHTTPRequest和AFNetworking,結合了兩個庫的共同特色, 而且有一些新的特性。除此以外,MKNetworkKit可能會比其餘網絡庫而言爲了代碼的清晰性,要求你寫一丁點多的代碼。用了 MKNetworkKit,你很難寫出醜陋的網絡代碼。

特性

超輕量級

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

完整的庫只有2個主類和一些category方法。也就是說,採用MKNetworkKit是很是容易的。

整個應用共享單一隊列

嚴重依賴網絡鏈接的應用應該優化他們的網絡併發鏈接數。十分不幸的是,如今尚未網絡庫能夠正確的完成這些功能。讓我來舉個例子說明若是你不去優化或者控制網絡的併發鏈接數會發生什麼。

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 queue sizing 自動隊列大小

咱們繼續前一個討論。我說了移動網絡不容許同時超過兩個併發網絡請求。因此當3G網絡時你的隊列大小應該設爲2,MKNetworkKit自動爲你 處理這些。當網絡進入3G/EDGE/GPRS時,它會更改併發鏈接的數目爲2,而且在鏈接wifi時自動設置回6。有了這個特性,你會看到當你經過3G 網絡從服務器加載縮略圖(或者多個小的請求)時有巨大的性能提高

Auto caching 自動緩存

MKNetworkKit能夠自動緩存你的全部GET請求。當你發起一樣一個請求的時候,MKNetworkKit會當即用緩存的響應(若是有)來 調用完成方法,也會向遠程服務器發出一個請求。當服務器的數據返回之後,會用取到的新的相應再次調用完成方法。這就是說,你不須要手動的處理緩存,你須要 作的,就只有調用這個方法:

[[MKNetworkEngine sharedEngine] useCache];

固然,你也能夠在你的MKNetworkEngine子類中定製緩存的目錄和內存緩存的消耗量。

Operation freezing 操做凍結

用了MKNetworkKit,你就擁有了凍結網絡操做的能力。當你凍結一個操做的時候,爲了防止網絡鏈接丟失,操做會被自動序列化而且在設備聯網以後自動執行。想一想微博客戶端的草稿箱功能。

當你發送一條微博時,把這個網絡操做標記爲凍結,MKNetworkKit會自動的處理凍結和解凍工做!而後這條微博你不用寫一行代碼就會自動稍後 發送。你可使用在好比標記一條微博爲喜歡或者從google reader客戶端分享一篇文章或者添加一個鏈接到instpaper等相似場景中。

Image Caching 圖片緩存

MKNetworkKit能夠無縫的緩存縮略圖。經過重寫幾個方法,你能夠設置緩存多少張圖片在內存緩存以及緩存的目錄。重寫這些方法徹底是可選的。

Performance 性能

一個詞:速度。MKNetworkKit的緩存是無縫的,就像NSCache同樣工做,除此以外,當內存警告的時候,內存緩存會寫入到緩存目錄中。

Full support for Objective-C ARC 全面支持Ojbective-C ARC

通常你會爲新的項目選擇一個新的網絡庫。MKNetworkKit不是爲了取代你現有的(固然你也能夠取代,可是可能會很麻煩)。在新的項目中,你 會很想要使用ARC功能。MKNetworkKit多是惟一全面支持ARC的網絡庫。基於ARC管理的代碼速度可能比非ARC的代碼是數量級的差距。

How to use 如何使用

OK,不自吹了,讓咱們來看看如何使用這個framework。

Adding the MKNetworkKit  添加MKNetworkKit

  1. 拖拽MKNetworkKit的目錄到你的工程裏
  2. 添加 CFNetwork.Framework, SystemConfiguration.framework and Security.framework 依賴庫
  3. 在PCH文件中包含 MKNetworkKit.h
  4. 刪除 NSAlert+MKNetworkKitAdditions.h若是你開發的是iOS程序。
  5. 刪除 UIAlertView+MKNetworkKitAdditions.h若是你開發的是Mac程序。

就是這樣子,僅僅5個核心文件,媽媽不再用擔憂網絡請求了。

 MKNetworkKit 中的類

  1. MKNetworkOperation
  2. MKNetworkEngine
  3. 混雜的幫助類 (蘋果的 Reachability) 以及一些cateogory方法。

我相信簡潔就是美。蘋果已經把實際網絡操做的繁重工做都作了,因此第三方的網絡庫應該提供的就是一個優雅的隊列和可選的緩存。我堅信,任何第三方的 庫都應該少於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來獲取雅虎財經的貨幣交換率。

第一步: 建立一個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];

注意,雅虎不須要你發送x-client-identifider在header裏面,因此上面的例子僅僅是爲了演示這個功能特性。

既然代碼都是ARC的,那麼是否對Engine的實例進行strong引用取決於開發者。

當你建立一個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;

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裏面,咱們使用一種新的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__]

你寫的方法應該按照以下順序執行:

  1. 準備好url和請求參數
  2. 建立一個請求的MKNetworkOperation對象.
  3. 設置方法參數
  4. 添加完成和錯誤處理方法,(完成方法就是你處理你響應到相應的model類的地方)
  5. 可選的,還有請求操做的進度指示。(或者在viewController裏面處理)
  6. 若是你的操做時下載文件,那麼設置一個下載的流(一般是一個文件)給他,這也是可選的
  7. 當請求操做完成時,處理結果而且調用block方法來向調用方法返回數據。

下面是實例代碼:

        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;

上面的代碼構造url而後建立了MKNetworkOperation,設置完完成方法和錯誤處理方法以後就把他經過調用父類的 enqueueOperation方法放入隊列中,而且返回一個引用。你的viewController應該持有這個操做而且在 viewController彈出視圖體系的時候取消網絡操做。因此你能夠在viewDidAppear裏面調用engine的方法,而且在 viewWillDisappear裏面取消操做。取消操做會釋放隊列從而使隊列繼續其餘操做(記住,在移動網絡中僅僅容許2個併發請求,取消不在須要的 操做能夠提高性能,加速你的app)

你的ViewController也能夠(可選的)添加進度處理,而且更新界面,下面就是如何作

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

        DLog(@"%.2f", progress*100.0);
        self.uploadProgessBar.progress = progress;
    }];

MKNetworkEngine也能夠很方便的根據url來建立請求,因此下面代碼能夠寫爲:

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

注意請求的url是自動在初始化engine的代碼裏面加上提供的域名。

建立一個POST,DELETE或者PUT的方法同樣簡單,就是更換http方法的參數。MKNetworkEngine也有更多給你多的便利指出好比讀取header文件

示例 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];

凍結的操做會在網絡不通時自動的被序列化而且上線後自動執行。想一下在離線時標記一條微博爲喜歡而後稍後上線以後操做會自動執行。凍結的操做也會被持久化到磁盤當app進入後臺以後。而且會在稍後app恢復以後自動執行。

 MKNetworkOperation中的便捷方法

MKNetworkOperation 提供了一些以下便捷方法來方便你格式化你的響應數據

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

從網絡請求獲取響應很方便,當返回格式錯誤時,這些方法返回nil,好比試圖從響應爲html中獲取image會返回nil,惟一能夠確保返回正確結果的方法時responseData,若是你肯定返回類型,能夠用其餘方法。

方便宏定義

宏定義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

相關文章
相關標籤/搜索