我最近在做一個(gè)表情SDK的項(xiàng)目,SDK本身已經(jīng)打包完成了,但是在與第三方開發(fā)者對接的時(shí)候,遇到了一些問題。我之前沒有考慮到這樣的問題,所以就寫一篇文章記錄一下。
很多人開發(fā)的時(shí)候都會(huì)用到第三方庫,尤其是像AFNetWorking這樣的庫。接入第三方庫可以讓我們不必重復(fù)造輪子,縮短開發(fā)周期。而且對于某些已經(jīng)成熟的第三方庫,想要造一個(gè)比它更好的輪子是需要下一番苦功夫的,對于初學(xué)者來說,沒有那個(gè)精力,也沒有那個(gè)能力去造這么龐大的一個(gè)輪子。
我遇到的問題就是關(guān)于第三方庫AFNetworking的,我在SDK里面的HTTP請求都是依靠AFNetworking實(shí)現(xiàn)的,而和我對接的第三方開發(fā)者也同樣是調(diào)用了AFNetworking來實(shí)現(xiàn)HTTP請求,本來這并沒有什么問題。但是,眾所周知,去年AFNetworking發(fā)布了3.0版本。3.0版本是一次大升級,很多接口的調(diào)用都不一樣了,內(nèi)部實(shí)現(xiàn)原理也改變了很多。不巧的是,我用的是3.0的版本,而對方用的是2.0的版本。而且對方因?yàn)槟承┰?,暫時(shí)不能升級到3.0,要求我們提供一個(gè)降級的版本,這下可讓我頭大了。
由于之前我沒有對AFNetworking進(jìn)行封裝,代碼里大量充斥著AFNetworking的函數(shù),如果要降級,涉及到這些函數(shù)的地方我都得花精力去修改。并且,由于SDK未來還要和其他開發(fā)者對接,所以我必須要同時(shí)維護(hù)兩份代碼,來分別應(yīng)對調(diào)用了3.0版本的開發(fā)者和2.0版本的開發(fā)者,這實(shí)在是太消耗時(shí)間精力了。
此時(shí)此刻我才意識到封裝第三方庫是有多么的重要,如果我之前封裝過AFNetworking的話,那我只需要將封裝的那個(gè)類里的每個(gè)函數(shù)修改一下就足夠了。
因此,我創(chuàng)建了一個(gè)類,用來封裝第三方庫,就拿AFNetworking來舉例好了。我將常用的HTTP請求函數(shù)封裝了起來,如下所示。
+ (void)sendGetWithURL:(NSString *)url parameterDic:(NSDictionary *)parameterDic completionHandler:(send_request_completed_block)block;
+ (void)sendPostWithURL:(NSString *)url parameterDic:(NSDictionary *)parameterDic completionHandler:(send_request_completed_block)block;
+ (void)sendPutWithURL:(NSString *)url parameterDic:(NSDictionary *)parameterDic completionHandler:(send_request_completed_block)block;
+ (void)sendDeleteWithURL:(NSString *)url parameterDic:(NSDictionary *)parameterDic completionHandler:(send_request_completed_block)block;
回調(diào)定義如下所示,返回兩個(gè)參數(shù)。一個(gè)是自定義的錯(cuò)誤碼,另一個(gè)則是解析好的JSON字典。
typedef void(^send_request_completed_block)(ECApiErrorCode errorCode,NSDictionary *resultDic);
這是Get請求封裝的具體實(shí)現(xiàn)
+ (void)sendGetWithURL:(NSString *)url parameterDic:(NSDictionary *)parameterDic completionHandler:(send_request_completed_block)block {
AFHTTPRequestOperationManager *manager = [self getOperationManager];
[manager GET:url
parameters:parameterDic
success:^(AFHTTPRequestOperation *operation, id responseObject) {
block(ECApiErrorCode_Success,responseObject);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
ECApiErrorCode errorCode = [self errorCodeTransformFromHTTPCode:operation.response.statusCode];
block(errorCode,nil);
}];
// AFHTTPSessionManager *manager = [self getSessionManager];
// [manager GET:url
// parameters:parameterDic
// progress:nil
// success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
// if (IS_NOT_A_VALID_DIC(responseObject)) {
// block(ECApiErrorCode_ServerDataError,nil);
// } else {
// block(ECApiErrorCode_Success,responseObject);
// }
// }
// failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
// NSHTTPURLResponse *response = (NSHTTPURLResponse *)task.response;
// ECApiErrorCode errorCode = [self errorCodeTransformFromHTTPCode:response.statusCode];
// block(errorCode,nil);
// }];
}
我還定義了一個(gè)單例用來管理這些請求的基本設(shè)置,例如超時(shí)時(shí)間,解析方式等。
//static AFHTTPSessionManager * s_manager = nil;
static AFHTTPRequestOperationManager * s_manager = nil;
//+ (AFHTTPSessionManager *)getSessionManager {
// static dispatch_once_t onceToken;
// dispatch_once(&onceToken, ^{
// s_manager = [AFHTTPSessionManager manager];
// s_manager.responseSerializer = [AFJSONResponseSerializer serializer];
// s_manager.requestSerializer = [AFJSONRequestSerializer serializer];
// s_manager.requestSerializer.timeoutInterval = 10;
// });
//
// return s_manager;
//}
+ (AFHTTPRequestOperationManager *)getOperationManager {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
s_manager = [AFHTTPRequestOperationManager manager];
s_manager.responseSerializer = [AFJSONResponseSerializer serializer];
s_manager.requestSerializer = [AFJSONRequestSerializer serializer];
s_manager.requestSerializer.timeoutInterval = 10;
});
return s_manager;
}
這樣就封裝好了。在我貼出來的這幾張圖里,未注釋的部分就是調(diào)用了AFNetworking2.0的做法,而注釋的部分就是調(diào)用了3.0的做法。如果我想要切換版本,只需要修改一下注釋的位置就可以了,十分方便。
也許有人會(huì)問:“如果我開發(fā)的項(xiàng)目不需要與其他開發(fā)者對接,那還有必要這樣封裝嗎?”。我的建議是,如果調(diào)用第三方庫的地方很多的話,還是要封裝起來比較好。我還是拿AFNetworking舉例子吧。萬一以后出了個(gè)4.0版本,又改了一大堆的接口調(diào)用方式呢?所以能封裝起來,盡量還是封裝起來比較好。