根據Coding的iOS端從新用RAC封裝網絡請求

很久沒寫博客了。個人博客地址。以前一直在研究MVVM這種新的開發模式。也算是沉澱了一段時間,國慶期間可能還會寫寫MVVM。今天要聊的是創萌工做室的iOS客戶端網絡請求的封裝。由於不少緣由封裝的還不夠好存在不少問題今天寫出來只是想把最近作的事情寫出來做個記錄。html

我寫這篇文章已經作好了被噴死吐槽死的準備了,由於我感受我封裝的太有問題了,可是又真的很想寫一寫,畢竟對我來講確實解決了一個大問題。ios

先簡單的說說咱們的網絡請求轉變過程

加入工做室一年。一共作了有三四個項目了。我先大概敘述一下咱們的網絡請求的轉變過程git

第一階段 直接調用AFNetworking

第一個項目那時候懵懂無知,每一個界面都直接調AFNetworking。這樣致使的問題就是代碼量驟然增長。github

第二階段 直接調用YTKNetwork

第二個項目剛作的時候唐巧開源了他們在猿題庫封裝的YTKNetwork。那時候仍是懵懂無知,仍是在每一個界面都開始直接調YTKNetwork。人家封裝的那麼好的東西就被我用成這個栽子,簡直對不起巧大。我記得有個界面好像有5條網絡請求,能夠想象代碼的冗餘度。json

第三階段 開始使用ReactiveCocoa

由於在作第二個項目的時候我和迪哥負責不一樣的客戶端。迪哥在看了limboy的基於AFNetworking2.0和ReactiveCocoa2.1的iOS REST Client開始將網絡請求剝離到一個專門的界面,這樣每次就不用寫不少的東西了。數組

limboy用了AFNetworking-RACExtensions來實現回調的效果。簡單的說就是subscribe一個信號,而後信號會返回一個信號回來,這樣就實現了將網絡請求部分剝離的效果。緩存

我在第二個項目基本上結束的時候上線了一個本身獨立開發的app,裏面就是用了這樣的方法。服務器

這學期在作項目的時候仍是在沿用迪哥的代碼,可是我發現了不少問題。網絡

一是limboy在寫rac代碼的時候用的concat沒法完成網絡請求再請求。簡單的說,服務器在返回告訴我session失效的時候我先須要後臺自動登陸而後再次網絡請求。我再寫的時候concat沒法實現再次網絡請求,我也不太明白爲何,試了各類方法都不行。這是很困惑個人我後面還須要再次研究一下。session

二是再判斷服務器返回的東西的時候,須要判斷狀態碼。若是成功,那麼會有json數據返回回來,若是失敗則沒有數據。出現這樣的狀況若是我在Acontroller調Bcontroller的網絡請求則還須要判斷是否是返回了一個數組或者對象,若是是,開始對數據進行處理,若是不是,還得從新進行網絡請求,由於說明session失效了。

這樣仍是致使了網絡請求部分有大量的代碼。

根據Coding的iOS從新封裝網絡請求

Coding的iOS客戶端是開源的,在Github和Coding官網都有。我放的連接是一個下載下來就能跑起來的。(強迫症,跑不起來的代碼都不想看..不過如今看MVVM好多都跑不起來也硬着頭皮看了)

Coding的網絡請求本身看了。Coding是用block來進行回調的。至於這一塊選擇notice仍是block仍是delegate,能夠參考iOS應用架構談 網絡層設計方案我算是認真看了,可是不是很能寫的出來...

插一句話,咱們爲何不用block。由於迪哥也不太會block就直接上rac了,我以前的博客寫過簡單的block,我在寫代碼的時候用delegate和notice比較多因此對block的實踐比較少。這是我自身的問題。並且說實話我以爲用rac挺好的,由於block加上typedef啥的其實不少東西的,不像rac直接調就完事了。

下面開始今天的算是乾貨的東西

1. 分析Coding網絡請求

Coding的網絡請求我以爲能夠總結爲

block -> block -> AFNetworking

下面來解釋一下,首先第一個block是咱們的主viewcontroller,也就是咱們邏輯部分和視圖部分。首先第一個block調Coding_NetAPIManager裏的函數。而後在Coding_NetAPIManager再調CodingNetAPIClient裏的函數。

(具體Coding代碼請看Coding客戶端代碼的連接)

咱們倒着來講。

第三部分 AFNetworking

在我分類的AFNetworking裏也就是CodingNetAPIClient裏,Coding進行了一件事情,那就是進行AFNetworking的網絡請求。

在獲取到數據的時候的對reponse進行一個判斷。在判斷數據的時候,若是數據有錯誤,則直接顯示錯誤的msg,若是沒有錯誤,那麼則不返回任何東西。

而後在網絡請求中判斷,若是有錯誤,那麼返回nil和id類型的error。若是沒錯誤,返回response和nil。

第二部分 block

在這部分裏,回調的結果有兩種,一種是有數據,一種是沒數據。其實到這就好了。那麼如今在這第二個部分幹什麼呢,json轉model。就這麼簡單。返回的東西,若是有數據返回,那麼就再次返回model或者是data和nil,若是沒有數據返回,就返回nil和error。

第一部分 block

到這裏,其實只要判斷有無數據就能夠啦。

好了。下面咱們只須要用RAC來替換block就完成了。固然了,中間有坑,不會那麼簡單的...

2. 改寫網絡請求

我要上代碼了。依然三部分。咱們仍是倒着來。我放關鍵的代碼在這。

既然我把Coding的代碼分紅了

block -> block -> AFNetworking

那麼個人基本上就能夠說是

RAC -> RAC -> AFNetworking

也是倒着來。

第三部分 AFNetworking

這是AFNetworking網絡請求

//一切仿照Coding
case Get:{
    return [[[[self rac_GET:aPath parameters:params] map:^id(RACTuple *JSONAndHeaders) {
        NSDictionary *responseObject = JSONAndHeaders[0];
        DebugLog(@"\n===========response===========\n%@:\n%@", aPath, responseObject);
//這裏調用下一個部分的函數
        id error = [self handleResponse:responseObject autoShowError:autoShowError rerequestJsonDataWithPath:aPath withParams:params withMethodType:method];
        if (error) {
            return RACTuplePack(nil, error);
        }else{
            return RACTuplePack(responseObject, nil);
        }
    }]
             catch:^RACSignal *(NSError *error) {
                 DebugLog(@"\n===========response===========\n%@:\n%@", aPath, error);
                 return [self showError:error];
             }] replayLazily];
    break;
}
-(id)handleResponse:(id)responseJSON autoShowError:(BOOL)autoShowError
rerequestJsonDataWithPath:(NSString *)aPath
         withParams:(NSDictionary*)params
     withMethodType:(NetworkMethod)method{
    NSError *error = nil;
    NSNumber *resultCode = [responseJSON valueForKeyPath:@"status"];
    
    //若是服務器返回的值不是正確有數值的話
    if (resultCode.intValue != VALUE) {
        error = [NSError errorWithDomain:BASE_URL code:resultCode.intValue userInfo:responseJSON];
        //若是服務器返回session失效的錯誤碼
        if (resultCode.intValue == VALUE) {//用戶未登陸
            [[[NetWork sharedManager] login] subscribeNext:^(RACTuple *x) {
                RACTupleUnpack(id data) = x;
                //因爲沒登錄那麼這裏調用第二個部分RAC的登錄方法,進行從新登錄
                if (data) {
                //這時有數據返回則再次發出網絡請求
                    [self rerequestJsonDataWithPath:aPath withParams:params withMethodType:method];
                } else {
                    
                }
            }];
        }else{
            if (autoShowError) {
                [self showError:error];
            }
        }
    }
    return error;
}
//這是從新登錄後再次進行網絡請求
- (void)rerequestJsonDataWithPath:(NSString *)aPath
                      withParams:(NSDictionary*)params
                  withMethodType:(NetworkMethod)method
{
    [[[NetWorkCheck sharedJsonClient] requestJsonDataWithPath:aPath withParams:params withMethodType:Get] subscribeNext:^(id x) {
        NSLog(@"success");
    }];
}

第二部分 RAC

- (RACSignal *)test2
{
    NSString *path = @"/MyList.do";
    
    NSDictionary *params = @{@"id":@"22"};
    
    return [[[NetWorkCheck sharedJsonClient] requestJsonDataWithPath:path withParams:params withMethodType:Get] map:^id(RACTuple *x) {
        RACTupleUnpack(id resultData, NSError *error) = x;
        if (resultData) {
            return RACTuplePack(resultData, nil);
        } else {
            return RACTuplePack(nil, error);
        }
    }];
}

第一部分 RAC

- (IBAction)test2:(id)sender
{
    [[[NetWork sharedManager] test2] subscribeNext:^(RACTuple *x) {
        RACTupleUnpack(id data) = x;
        if (data) {
            
        }
    }];
}

看代碼的時候最好是從第一部分看,我爲了突出重點因此把第三部分放到最前面了。基本上我就幹了一件事情,把block改寫爲RAC。

3. 問題以及填坑

問題一:回調兩個值

其實用RAC改寫block是不難的,難的在於block傳值傳了兩個回去,RAC我沒找到能夠傳兩個值的地方,因而我用了RACTuplePack,這個是RAC裏一個宏定義,能夠打包變量。而後在信號收取端利用RACTupleUnpack(id resultData, NSError *error) = x;來解加壓縮變量(用詞不許確見諒)

在這裏很是感謝這樣好用的ReactiveCocoa,根本停不下來這篇博客。看到了RACTuplePack這個宏定義。

問題二:如何在服務器返回session失效以後進行兩次連接請求,一次後臺自動登陸,一次從新進行網絡請求

在Coding的代碼裏,我看到若是未登陸是會彈出登陸界面。可是咱們要求是後臺登陸而後從新請求。

我開始是想在get請求那部分直接在此調get的網絡請求。可是不會執行兩次網絡請求。

以前的項目是在vc的界面判斷沒數據則在此調用函數。若是那樣的話我不是白封裝半天了...因而決定封裝到network裏,我就在從新登陸後判斷有無數據,有數據則意味着登陸成功,登陸成功,在此調一個登陸的函數。

雖然這樣看上去就不合理,可是是我能嘗試出來的一個辦法了...嘗試了好幾天,查了半天也沒有相似的解決方案。

問題三:爲何有時候不會執行網絡請求

我在解決問題二的時候就出現這種問題,不能進行網絡請求,我只是一個簡單的調函數。可是,可是,可是,在rac裏必需要subscribeNext,若是不subscribeNext則不會調!這是須要記住的。

4. 還存在的問題以及不足

  1. Coding對於Get請求還作了緩存,我沒作。後面會慢慢加上。

  2. RAC是對於不少東西的一個大集合,好比block好比KVO等等。因此須要對iOS的內存管理機制進行一個深刻理解,這是我一直所欠缺的。這個問題在我解決問題二的時候出現了好幾回報錯,都是這個問題。可是我卻沒法解決。

  3. Coding中還用到了不少顯示錯誤的MBProgress等等,我在此都沒寫,若是想仔細研究去看Coding的源碼。

  4. Coding的網絡請求還有不少對文件的處理,post請求等等,我如今只改寫了Get和Post請求。後面須要把Coding這一套都好好的研究一下。

  5. 對於RAC的理解仍是不夠,在整個過程當中遇到不少問題。

最後的最後感謝Coding將他們的客戶端開源出來,感謝爲Coding貢獻代碼的工程師。是大家讓我學到了更多的東西?

相關文章
相關標籤/搜索