Coding iPad 客戶端源代碼

來自: https://github.com/Coding/Coding-iPad

Coding-iPad客戶端說明

Just run it!

想要看看 iPad 版本什么樣,沒問題! clone 或者下載代碼后,初次執行時,雙擊根目錄下的 bootstrap 腳本,該腳本會準備初始數據,完成后會打開工程,點擊 Xcode 運行!So easy,媽媽再也不用擔心我的代碼編譯出錯了!(之后只需打開 CodingForiPad.xcworkspace 即可)

嗯……,你的代碼好像很棒,請告訴我xx是怎么做的

先告訴大家代碼大概在哪里。

.
├── CodingForiPad
│   ├── Vendor:因為各種原因沒有用Pods管理的第三方庫
│   ├── Resources:資源文件
│   ├── Util:一些工具類,Category等
│   ├── Request:網絡請求
│   ├── Models:數據模型,一般一個網絡請求會對應一個model
│   ├── RequestExt:請求的業務擴展,用于分離基本請求以便于復用代碼
│   ├── ModelsExt:數據模型的業務擴展,用于分離基本模型以便于代碼復用
│   ├── Manager:一些單例
│   │   ├── AddressManager:iPhone版本代碼
│   │   ├── Coding_FileManager:文件上傳(iPhone版本代碼)
│   │   ├── COSession:登錄用戶管理
│   │   ├── COUnReadCountManager:讀信息、私信管理
│   │   ├── ImageSizeManager:iPhone版本代碼
│   │   ├── JobManager:iPhone版本代碼
│   │   ├── StartImagesManager:iPhone版本代碼
│   │   ├── TagsManager:iPhone版本代碼
│   │   └── WebContentManager:格式化為網頁使用,iPhone版本代碼 
│   └── ViewController
│       ├── Style:基本樣式,顏色等
│       ├── Custom:一些自定義的View
│       ├── Base:基本Controller
│       ├── User:用戶資料相關的UI
│       ├── Project:項目相關的UI
│       ├── Task:任務相關的UI
│       ├── Tweet:冒泡相關的UI
│       ├── Message:消息和私信相關的UI
│       └── Setting:設置相關的UI
└── Pods:項目使用了[CocoaPods](http://code4app.com/article/cocoapods-install-usage)這個類庫管理工具

有兩個比較隱蔽的問題,需要說明一下。首先,Coding 上部分資源是WebP格式,使用 SDWebImage 時,需要加入 WebP.framework;另外,在 Coding 的一些圖片需要驗證 Cookie 的,所以,在使用 SDWebImage 時,注意啟用 Cookie,增加 SDWebImageHandleCookies 選項,代碼如下所示:

[self.regCodeImageView sd_setImageWithURL:[NSURL URLWithString:url] placeholderImage:nil options:SDWebImageRetryFailed | SDWebImageHandleCookies | SDWebImageRefreshCached completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
    if (error) {
        dispatch_async(dispatch_get_main_queue(), ^{
            weakself.regCodeImageView.image = [UIImage imageNamed:@"captcha_loadfail"];
        });
    }
}];

iPad 客戶端使用了 Storyboard,所以在代碼閱讀上,建議先從 Storyboard 開始,了解整個項目的脈絡(由于項目比較大,打開 Storyboard 項目的速度取決于機器的配置,Orz)。另外從 UI 來入手也比較直觀,在 Storyboard 中也可以直接看到 UI 對應的 Controllor。

關于 ViewControllerr目錄的組織基本是按照 UI 上展現來組織的,比如 Tweet 目錄,主要是存放冒泡相關實現的代碼,而其所對應的網絡請求和 Models 也都是 COTweet 開頭,這樣大家很容易提綱挈領從一點貫通全面。

RequestExt 和 ModelsExt 目錄下是與業務比較相關的請求和模型,這樣做是為了使數據請求和模型與業務邏輯無關,保證這部分代碼能夠復用。

很好,我也要寫一個這么棒的Coding客戶端

沒問題,現在來告訴大家,怎么復用代碼。

不過,略微有點遺憾,由于項目比較緊張,當前只有網絡請求和 Model 可以輕松復用。

首先,再講一個隱蔽的問題,關于用戶登錄!Coding 的用戶驗證是通過 Cookie 來驗證的,所以問題來了,如果你直接調用登錄接口,會發現登錄成功了,但是訪問其他接口會提示用戶未登錄,為什么呢,因為 Cookie 沒有存儲,為什么沒有存儲,因為你在登錄之前沒有請求驗證碼接口。所以,再你調用登錄接口之前, 必須先請求驗證碼接口!!!必須先請求驗證碼接口!!!必須先請求驗證碼接口!!! (重要的事情說三遍)

網絡請求

網絡請求時基于 AFNetworking 的,稍微封裝了一下,所有接口請求都是繼承于 CODataRequest。 Coding 是 RestFul 接口,HTTP 請求除了GET、POST,之外還有 PUT 和 DELETE 方法,所以在 CODataRequest 實現了上述四種基本請求方法。一個接口可能既支持 GET,也支持 DELETE,所需要的參數不盡相同。因此,我定義了幾個指示說明性的宏來標識請求和參數,如下所示:

#define COQueryParameters       // Get 參數
#define COUriParameters        // URI 參數
#define COFormParameters       // Post 參數

#define COGetRequest    /** Get請求 */
#define COPostRequest   /** Post請求 */
#define COPutRequest    /** Pust請求 */
#define CODeleteRequest /** Delete請求 */

以用戶登錄接口為例:

COPostRequest
@interface COAccountLoginRequest : CODataRequest

@property (nonatomic, copy) COFormParameters NSString *email;
@property (nonatomic, copy) COFormParameters NSString *password;
@property (nonatomic, copy) COFormParameters NSString *jCaptcha;
@property (nonatomic, copy) COFormParameters NSString *rememberMe;

@end

COPostRequest 表示這個接口是 POST 接口,調用的時候需要執行 postWithSuccess 方法;

COFormParameters 表示參數是 Post 使用的參數;

請求實現

CODataRequest 將一個請求分為了四個階段,請求準備,參數填充,完成準備,發起請求,數據解析。如果需要實現一個新請求,正常來說,需要完成請求準備和參數填充兩個階段,一般來說在準備階段我們主要設置請求的 path,代碼如下所示:

- (void)prepareForRequest
{
    self.path = @"/login";
}

參數準備主要是建立參數映射字典,將請求的參數映射為對應的接口參數,代碼如下:

- (NSDictionary *)parametersMap
{
    return @{
             @"email" : @"email",
             @"password" : @"password",
             @"rememberMe" : @"remember_me",
             @"jCaptcha" : @"j_captcha",
             };
}

其中 key 是請求的屬性,對應的 value 是接口的參數名。

數據解析階段是將接口返回的 JSON 封裝為 CODataResponse 對象,并將數據映射成對應的 Model,代碼如下:

- (CODataResponse *)postResponseParser:(id)response
{
    return [[CODataResponse alloc] initWithResponse:response dataModleClass:[COUser class] responseType:CODataResponseTypeDefault];
}

還有一個完成準備的階段,這是表示,參數準備就緒,可以開始了,這時,我們可能還需要做一些事情,比如我封裝了一個 COPageRequest,所有分頁請求的數據都繼承于它,讓我們看看,它是怎么做的:

- (void)readyForRequest
{
    NSMutableDictionary *params = [NSMutableDictionary dictionaryWithDictionary:self.params];
    [params setObject:@(self.page) forKey:@"page"];
    [params setObject:@(self.pageSize) forKey:@"pageSize"];
    self.params = [NSDictionary dictionaryWithDictionary:params];
}

COPageRequest 使用了 readyForRequest,將 page 和 pageSize 兩個參數追加到參數映射中,這樣其他的分頁請求就不需要在參數映射中寫這兩個參數了。

數據模型

數據模型采用了Mantle將 JSON 映射為對象。來看一個簡單的列子:

@interface COFileCount : MTLModel<MTLJSONSerializing>

@property (nonatomic, assign) NSInteger folderId;
@property (nonatomic, assign) NSInteger count;

@end

@implementation COFileCount

+ (NSDictionary *)JSONKeyPathsByPropertyKey
{
    return @{@"folderId" : @"folder",
             @"count" : @"count",
             };
}

@end

是不是有些熟悉?沒錯,網絡請求也參考了 Mantle 的實現。同樣的 JSONKeyPathsByPropertyKey 中,key 對應的是 Model 的屬性,value 對應的是 JSON 中的數據名。

復雜模型的建立,請詳細參考 Mantle 的文檔。

請求與模型的橋梁

CODataResponse 是請求于模型之間的橋梁。CODataResponse 封裝了整個網絡請求返回數據,包含了code、msg、error以及數據等。所以,一個網絡請求返回后,我們需要先檢查 CODataResponse 中的 code,如果 code 為0,則表示請求 OK,然后還需要判斷 error,這個 error主要是我們解析數據時產生的錯誤,多數是模型建立的不對,或者接口模型調整導致的。

因為 Coding 的接口返回比較規范,主要是三種形式,字典,列表和 Pageable,因此 CODataResponse 封裝了這三種形式的數據解析,解析數據變的非常簡單,代碼如下所示:

- (CODataResponse *)postResponseParser:(id)response
{
    return [[CODataResponse alloc] initWithResponse:response dataModleClass:[COUser class] responseType:CODataResponseTypeDefault];
}

這是用戶登錄接口的數據解析,是不是很容易?

代碼使用

拷貝 Request 和 Model 目錄到你的項目中,在 Podfile 中添加如下兩行:

pod 'AFNetworking'
pod 'Mantle'

代碼復用從未如此輕松……

好了,揚帆起航

你可以專注于 UI 和交互了,去寫一個牛閃閃的 Coding 客戶端吧!

License

MIT

 本文由用戶 NMKMilford 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!