背景和目的
目前iOS框架中網(wǎng)絡(luò)的實(shí)現(xiàn)方式大多基于流行的網(wǎng)絡(luò)框架進(jìn)行例如ASI、AFNetWork等)或者蘋果自帶的NSURLSession。ASI是基于CFHTTP的,AFNetworking是基于NSURL的,兩者處在不同的層次上,實(shí)現(xiàn)原理也不同。
如何在開發(fā)自己的項(xiàng)目過程中提供一套最簡單的API,只需提供我們用的到的接口,并且將一些重復(fù)的處理邏輯封裝起來。使得調(diào)用者在不需要了解到具體使用何種網(wǎng)絡(luò)庫 CFHTTP、NSURL、ASIHTTPRequest、AFNetworking的情況下,就能把網(wǎng)絡(luò)請求處理完,讓開發(fā)著處理網(wǎng) 絡(luò)請求像調(diào)用本地方法一樣自然,這就是本次設(shè)計(jì)的目的。
需要解決的問題
1.調(diào)用方式簡單明確
減少使用者對具體的網(wǎng)絡(luò)框架的依賴,按照統(tǒng)一的方式進(jìn)行調(diào)用,便于規(guī)范代碼書寫和后續(xù)維護(hù)。
2.解決網(wǎng)絡(luò)數(shù)據(jù)和業(yè)務(wù)層的對接問題
返回?cái)?shù)據(jù)形式是NSDictionary,在model基類中通過runtime方式將其轉(zhuǎn)換為具體的model對象。
3.業(yè)務(wù)層獲得數(shù)據(jù)的形式
業(yè)務(wù)層直接對具體的model進(jìn)行處理和顯示。為了減少業(yè)務(wù)層處理邏輯建議server端返回?cái)?shù)據(jù)形式盡可能和APP的UI表示邏輯保持一致。
4.封裝API應(yīng)該是集約型還是離散型
所謂集約型,就是只能業(yè)務(wù)層提供一個(gè)方法,所有業(yè)務(wù)層的網(wǎng)絡(luò)請求都要通過該方法完成。集約型的好處是對于網(wǎng)絡(luò)層的編寫來說方便快捷,對業(yè)務(wù)的適用性較強(qiáng)。
離散型就是根據(jù)功能模塊分為不同的模塊,分別提供不同的方法給業(yè)務(wù)層調(diào)用。離散型便于理解,項(xiàng)目結(jié)構(gòu)更清晰同時(shí)要求對業(yè)務(wù)具有較好的抽象能力。
本次設(shè)計(jì)采用集約型的方式進(jìn)行主要出于以下幾點(diǎn)考慮:
1.server支持的數(shù)據(jù)結(jié)構(gòu)貼近UI設(shè)計(jì),后續(xù)需要處理加工較少。
2.APP整體架構(gòu)設(shè)計(jì)時(shí)已經(jīng)對Control層進(jìn)行了擴(kuò)展,網(wǎng)絡(luò)訪問再使用離散型略顯啰嗦和導(dǎo)致代碼過于分散。
網(wǎng)絡(luò)架構(gòu)需要具備如下功能
1.支持緩存網(wǎng)絡(luò)請求內(nèi)容
2.支持統(tǒng)一設(shè)置服務(wù)器地址
3.支持檢查返回Json數(shù)據(jù)的合法性
4.支持block和delegate兩種模式的回調(diào)方式
5.支持批量的網(wǎng)絡(luò)請求,并統(tǒng)一設(shè)置它們的回調(diào)
6.支持網(wǎng)絡(luò)請求URL的filter,可以統(tǒng)一為網(wǎng)絡(luò)請求加上一些參數(shù),或者修改一些路徑。
網(wǎng)絡(luò)架構(gòu)圖
UML設(shè)計(jì)
最終實(shí)現(xiàn)
1.HTRequestConfig:負(fù)責(zé)配置統(tǒng)一服務(wù)器地址和為網(wǎng)絡(luò)請求加上一些參數(shù)(Token,Sig等),可同時(shí)為多個(gè)Request提供配置
2.HTRequest:基本的請求對象,請求的URL、參數(shù)、body數(shù)據(jù)體和請求的方法(Get、Post)
3.HTReponse:請求的返回?cái)?shù)據(jù)
4.HTNetWorkError:返回錯(cuò)誤信息
5.HTDataCache:數(shù)據(jù)緩存和讀取
類實(shí)現(xiàn)
HTRequestConfig
#import <Foundation/Foundation.h> @interface HTRequestConfig : NSObject @property (nonatomic,retain) NSString *baseUrl; @property (nonatomic,retain) NSString *token; @property (nonatomic,retain) NSString *sig; @property (nonatomic,retain) NSString *timestamp; @end
HTRequest
HTRequest通過其類方法進(jìn)行構(gòu)造,對外屬性均為只讀。其中tag用于批量請求時(shí)進(jìn)行區(qū)分。
#import "HTRequestConfig.h" typedef NS_ENUM(NSInteger, RequestMethod) { RequestMethod_Get = 0, RequestMethod_Post, RequestMethod_Put, RequestMethod_Delete };
@interface HTRequest : NSObject @property (readonly,nonatomic,copy) NSURL* url; @property (readonly,nonatomic,copy) NSString* fullPath; @property (readonly,nonatomic,copy) NSDictionary* parameters; @property (readonly,nonatomic,copy) NSData* data; @property (readonly,nonatomic)RequestMethod methodType; @property (nonatomic,retain)NSString *tag;
+ (instancetype)sharedRequestWithMethodType:(RequestMethod)methodType withPath:(NSString *)path withParam:(NSDictionary *)paramDic withConfig:(HTRequestConfig *)config;
+ (instancetype)sharedRequestWithData:(NSData *)data withPath:(NSString *)path withParam:(NSDictionary *)paramDic withConfig:(HTRequestConfig *)config; @end
HTNetWorkClient
HTNetWorkClient中集約所有訪問方法,包括單個(gè)和批量請求、數(shù)據(jù)上傳(圖片、音頻、視頻)支持block和delegate兩種模式的回調(diào)方式。
1.屬性defaultCheckMessage用于檢查json的合法性。在和Server端通信設(shè)計(jì)中規(guī)定所有Json的格式按照(MessageCode、Message、data)的形式進(jìn)行,messageCode非0的場合數(shù)據(jù)請求失敗。
2.屬性defaultUseCache用于設(shè)置和判斷是否有數(shù)據(jù)緩存,如果要使用緩存數(shù)據(jù)通過getCacheData進(jìn)行取得。
@interface HTNetWorkClient : NSObject{ AFHTTPSessionManager *_requestManager; NSInteger _bacthRequestCount; HTResponse *_batchResponse; }
@property (nonatomic,weak) id<HTRequestDelegate> delegate; @property (nonatomic)BOOL defaultCheckMessage; @property (nonatomic)BOOL defaultUseCache;
+ (instancetype)sharedClient;
- (void)startAsynchronous:(HTRequest *)request;
- (void)startAsynchronous:(HTRequest*)request onProgress:(HITResponseProgress)progressBlock onResponse:(HITResponseObject)responseBlock onError:(HITResponseError)errorBlock;
- (void)startAsynchronousWithBatchRequest:(NSArray *)batchRequest;
- (void)startAsynchronousWithBatchRequest:(NSArray *)batchRequest onProgress:(HITResponseProgress)progressBlock onResponse:(HITResponseObject)responseBlock onError:(HITResponseError)errorBlock;
- (void)startUploadData:(HTRequest *)request withDataType:(DataType)dataType;
- (void)startUploadData:(HTRequest *)request withDataType:(DataType)dataType onProgress:(HITResponseProgress)progressBlock onResponse:(HITResponseObject)responseBlock onError:(HITResponseError)errorBlock;
- (void)cancel;
- (id)getCacheData:(HTRequest *)request;
@end
HTNetWorkError
封裝錯(cuò)誤信息,無論請求是否正常json中messageCode不等于0即為失敗。
@interface HTNetWorkError : NSObject
@property (nonatomic,assign) NSInteger errorCode;
@property (nonatomic,copy) NSString *errorDescription;
@end
HTDataCache
按照訪問的url為key進(jìn)行數(shù)據(jù)緩存。
@interface HTDataCache : NSObject{ NSCache *_cache; }
+ (HTDataCache *)sharedManager;
- (void)cacheDataWithUrl:(NSString *)url withData:(id)jsonData;
- (id)getCacheDataWithUrl:(NSString *)url;
@end
HTResponse
封裝了請求的返回?cái)?shù)據(jù),有多個(gè)請求時(shí)以請求的tag作為key。
@interface HTResponse : NSObject{ NSMutableDictionary *_responseObjectDic; }
@property (readonly,nonatomic,strong)id object;
@property (readonly,nonatomic,strong)NSDictionary *objectDic;
+ (HTResponse*)shareResponseWithObject:(id)responseObject;
- (void)setObjectByKey:(NSString *)key withObject:(id)responseObject;
- (id)getObjectByKey:(NSString *)key;
@end