Objective-C的MKNetworkKit開發架構解析_IOS

來源:互聯網
上載者:User

什麼是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 是單例的,而是說它的共用隊列是單例的。


常用架構比如:AFNetworking,ASIHttpRequest,SDWebImage,MKNetWorKit等。
現在MKNetWorkKi吸取了ASIHttpRequest與AFNetWorking的優點,並加入了自己特有的功能。

下載:

gitHub地址:https://github.com/MugunthKumar/MKNetworkKit.git

官方使用說明:http://blog.mugunthkumar.com/products/ios-framework-introducing-mknetworkkit/

github下載了該項目後,如果想運行其demo,一定要開啟MKNetworkKit.xcworkspace該檔案,若單獨開啟,則編譯時間會提示缺少libMKNetworkKit-iOS.a檔案!!!

安裝:

複製下來之後把其中的 MKNetworkKit檔案夾拖入項目,然後引入3個framework:

注意:由於MKNetworkKit支援ARC,我們在項目中要開啟ARC,不然會報錯

開啟ARC自動記憶體控制機制:(開啟ARC之後項目中所有的dealloc 、release 、autorelease都得注釋掉)

使用方法:

  在需要使用的地方匯入:#import"MKNetworkKit.h"
正確顯示網路狀態指示

許多第 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

將 MKNetworkKit 目錄拖到項目中

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

將 MKNetworkKit.h 標頭檔包含到 PCH 檔案中

對於 iOS,刪除 NSAlert+MKNetworkKitAdditions.h

對於 Mac,刪除 UIAlertView+MKNetworkKitAdditions.h

總共只需要 5 個核心檔案,真是一個強大的網路開發包

MKNetworkKit 的類

MKNetworkOperation

MKNetworkEngine

一些工具類 (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&f=sl1d1t1&s=%@%@=X", __C1__, __C2__]

按如下順序編寫 engine類方法:

根據參數準備 URL

建立一個 MKNetworkOperation 對象

設定方法參數

設定 operation 的 completion 塊和 error 塊(在 completation 塊中處理 response 並轉換為模型)

可選地,添加一個 progress 塊(或者在 view controller 中做這個)

如果 operation 是下載,設定下載流(通常是檔案)。這步也是可選的

當 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 資料:

複製代碼 代碼如下:

responseData

responseString

responseJSON (Only on iOS 5)

responseImage

responseXML

error


當 operation 執行完時,這些方法被用於擷取響應資料。如果格式不正確,方法會返回nil。例如,響應的資料明明是一個 HTML 格式,你用 responseImage 方法只會得到 nil。只有 responseData 能保證無論什麼格式都返回正確,而其他方法你必須確保和相應的repsone 類型匹配。

有用的宏

DLog 和 ALog 宏被無恥地從 Stackoverflow 剽竊來了,我找不到源作者。如果是你寫的,請告訴我。

關於GCD 的一點說明

因為網路線程有可能會能被停止或優先處理,我果斷放棄了 GCD——GCD 的效率是比NSOperation 高,但它做不到這一點。我建議在你的網路線程中也不要使用基於 GCD 的隊列。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.