一、YTK的Git庫地址
https://github.com/yuantiku/YTKNetwork/blob/master/Docs/BasicGuide_cn.md
里面有YTK的中文說明,以及一些場景的用法,下面我們來看一下我們項目的一些使用場景
二、基類的封裝
1、我們現(xiàn)在所用的接口請求是在YTK的基礎(chǔ)上在封裝了一層(房信平臺封裝了2層,因為要加上緩存以及加密等邏輯),那房信平臺的FangChaChaRequest來說,繼承于EtopBaseRequest,EtopBaseRequest主要做了設(shè)置接口的請求方式(有兩種請求方式,POST和GET,注上兩者區(qū)別https://www.cnblogs.com/logsharing/p/8448446.html,一般都用POST(更安全));重寫自定義請求頭的方法,塞入請求頭的樣式;以及解析返回結(jié)果的格式(JSON,XML,Data三種,一般都用JSON);封裝調(diào)用請求的方法;


2、下面我們看FangChaChaRequest做了什么?
(1)首先涉及加密的邏輯處理,我們要對接口的請求參數(shù)進(jìn)行加密,這里的加密會每次根據(jù)App啟動隨機(jī)變成加密值,加密的代碼附上如下圖

(2)設(shè)置請求失敗提示時間(一般都是15s)
- (NSTimeInterval)requestTimeoutInterval {
// if (DEBUG) {
// return 5;
// }
return 15;
}
(3)重寫- (void)startWithCompletionHandlerWithSuccess:(nullable ETopRequestSuccessBlock)success failure:(nullable ETopRequestFailureBlock)failure方法,請求成功的時候先判斷開沒開起緩存,如果有先返回緩存數(shù)據(jù),這里一定要注意的是如果用戶開啟了緩存,即使緩存成功,我們也需在重新調(diào)用一次請求方法,更新緩存,否則每次拿到的都是頭一次緩存的結(jié)果;
a、請求成功

b、請求失敗,拿到錯誤信息,判斷是否是證書錯誤

(4)特別注意的是因為我們對請求參數(shù)進(jìn)行了加密,然后YTK的緩存是把請求參數(shù)當(dāng)做Key,前面有提過APP啟動的時候加密會隨機(jī),這個時候我們的緩存的Key變了,我們就拿不到上一次緩存數(shù)據(jù)的值,所以,我們加密后必須在FangChaChaRequest里面重寫YTK的獲取Key的- (id)cacheFileNameFilterForRequestArgument:(id)argument這個方法,返回我們未加密前的請求參數(shù)
- (id)cacheFileNameFilterForRequestArgument:(id)argument {
if ((NSNull *)self.unEncryptorArgument != [NSNull null] && self.unEncryptorArgument.count > 0) {
return self.unEncryptorArgument;
} else {
return argument;
}
}
三、應(yīng)用場景
1、緩存使用
在上面封裝完畢后,只需要在我們的API文件中,重寫- (NSInteger)cacheTimeInSeconds這個方法,并設(shè)置你想要緩存的時間(一般我們返回最大值)
- (NSInteger)cacheTimeInSeconds {
return NSIntegerMax;
}
2、異步請求
(1)YTK的異步請求適用于兩個接口之間沒什么依賴;但是YTK的異步請求會有一個接口請求失敗,接口就返回失敗;正常來說,邏輯也應(yīng)該這么處理,雖然兩個接口沒有依賴,但是如果一個界面有兩個接口,又是異步請求,如果不知道那個接口先回來,布局比較麻煩,所以還是一個接口接口失敗直接失敗處理比較好;最先我不會YTK的異步請求的時候?qū)懥艘粋€非常low的請求方法(捂臉),block里面調(diào)用block,請求成功調(diào)用一次,失敗在調(diào)用一次

所以使用YTK的異步請求后,我們只需要調(diào)用一個方法,也不需要寫這么多回調(diào)的block

(2)值得注意的是我們也在YTK的異步請求YTKBatchRequest做了一層我們項目邏輯的封裝FangChaChaBatchRequest,因為如果我們直接調(diào)用YTKBatchRequest,這個時候我們一些成功回調(diào)里面返回的其他狀態(tài)碼不會判斷,所以我們要在YTK的基礎(chǔ)上封裝一層加上我們邏輯處理的基類
- (void)startWithCompletionHandlerWithSuccess:(nullable ETopBatchCompletionBlock)success failure:(nullable ETopBatchCompletionBlock)failure {
[super startWithCompletionBlockWithSuccess:^(YTKBatchRequest *_Nonnull batchRequest) {
for (YTKRequest *request in batchRequest.requestArray) {
id responseObjec = [request responseJSONObject];
NSInteger statusCode = [responseObjec[@"StatsCode"] integerValue];
statusCode = (statusCode == 0 ? [responseObjec[@"status"] integerValue] : statusCode);
if (statusCode == SUCCEEDED_BatchRequest) {
if (success) {
success((ETopBatchRequest *)batchRequest);
}
} else {
if (statusCode == LoginFailCodeType) {
// 清空用戶信息
[LoginManager saveUserModel:nil];
} else if (statusCode == AuthorizationFailedCodeType) {
NSLog(@"重新獲取token");
[[DDOAuthClient shareInstance] getTokenAndLoginWithSuccess:nil];
}
if (failure) {
NSString *message = request.responseObject[@"Message"];
message = message ?: request.responseObject[@"msg"];
failure((ETopBatchRequest *)batchRequest);
}
}
}
}
failure:^(YTKBatchRequest *_Nonnull batchRequest) {
if (failure) {
// 失敗
NSString *description = batchRequest.failedRequest.error.localizedDescription;
description = [description stringByReplacingOccurrencesOfString:@"." withString:@""];
description = [description stringByReplacingOccurrencesOfString:@"。" withString:@""];
if (batchRequest.failedRequest.error.localizedRecoverySuggestion) { // 證書錯誤
NSData *errorData = [[NSData alloc] initWithData:[batchRequest.failedRequest.error.localizedRecoverySuggestion dataUsingEncoding:NSUTF8StringEncoding]];
NSDictionary *recoverySuggestion = [NSJSONSerialization JSONObjectWithData:errorData options:NSJSONReadingMutableLeaves error:nil];
if (recoverySuggestion) {
NSString *message = recoverySuggestion[@"Message"];
message = message ?: recoverySuggestion[@"msg"];
description = message;
}
}
failure((ETopBatchRequest *)batchRequest);
}
}];
}
3、同步請求
(1)同步請求適用于兩個接口直接存在依賴,第二個接口請求的參數(shù)必須從第一個接口請求成功后的結(jié)果而來,前面也提到過,我們請求的時候有自己的狀態(tài)碼邏輯處理,所以同理異步請求我們也需要做一層基于YTKChainRequest的封裝;同步請求不像異步請求,它的返回回調(diào)是兩個代理方法- (void)chainRequestFinished:(YTKChainRequest *)chainRequest(完成的代理方法),- (void)chainRequestFailed:(YTKChainRequest *)chainRequest failedBaseRequest:(YTKBaseRequest *)request (失敗的代理方法),所以我們在封裝的時候首頁要遵循代理,設(shè)置代理為自己以及請求成功和失敗的回調(diào),在請求成功后我們返回請求成功的block,失敗的時候判斷失敗的錯誤,并返回失敗的回調(diào)
a、初始化,遵循代理
- (instancetype)init
{
self = [super init];
if (self) {
self.delegate = self;
}
return self;
}
b、調(diào)用父類的同步請求方法,回調(diào)請求數(shù)據(jù)
- (void)addYTRequest:(ETopBaseRequest *)request callback:(nullable ETopChainCallback)callback{
[super addRequest:request callback:^(YTKChainRequest * _Nonnull chainRequest, YTKBaseRequest * _Nonnull baseRequest) {
if (callback) {
callback((ETopChainRequest *)chainRequest,(ETopBaseRequest *)baseRequest);
}
}];
}
c、實現(xiàn)請求成功的代理方法,加上項目的狀態(tài)碼等邏輯判斷,并且回調(diào)請求成功的數(shù)據(jù)
- (void)chainRequestFinished:(YTKChainRequest *)chainRequest {
for (YTKBaseRequest *request in chainRequest.requestArray) {
id responseObjec = [request responseJSONObject];
NSInteger statusCode = [responseObjec[@"StatsCode"] integerValue];
statusCode = (statusCode == 0 ? [responseObjec[@"status"] integerValue] : statusCode);
if (statusCode == SUCCEED_ChainRequest) {
if (self.ChainRequestSuccessBlock) {
self.ChainRequestSuccessBlock((ETopChainRequest *)chainRequest);
}
} else {
if (statusCode == LoginFailCodeType) {
// 清空用戶信息
[LoginManager saveUserModel:nil];
} else if (statusCode == AuthorizationFailedCodeType) {
NSLog(@"重新獲取token");
[[DDOAuthClient shareInstance] getTokenAndLoginWithSuccess:nil];
}
if (self.ChainRequestFailureBlock) {
NSString *message = request.responseObject[@"Message"];
message = message ?: request.responseObject[@"msg"];
self.ChainRequestFailureBlock((ETopChainRequest *)chainRequest, message);
}
}
}
}
b、實現(xiàn)請求失敗的代理,判斷是否是證書錯誤的邏輯判斷,并且返回失敗的數(shù)據(jù)和提示
- (void)chainRequestFailed:(YTKChainRequest *)chainRequest failedBaseRequest:(YTKBaseRequest *)request {
// 失敗
NSString *description = request.error.localizedDescription;
description = [description stringByReplacingOccurrencesOfString:@"." withString:@""];
description = [description stringByReplacingOccurrencesOfString:@"。" withString:@""];
if (request.error.localizedRecoverySuggestion) { // 證書錯誤
NSData *errorData = [[NSData alloc] initWithData:[request.error.localizedRecoverySuggestion dataUsingEncoding:NSUTF8StringEncoding]];
NSDictionary *recoverySuggestion = [NSJSONSerialization JSONObjectWithData:errorData options:NSJSONReadingMutableLeaves error:nil];
if (recoverySuggestion) {
NSString *message = recoverySuggestion[@"Message"];
message = message ?: recoverySuggestion[@"msg"];
description = message;
}
}
self.ChainRequestFailureBlock((ETopChainRequest *)chainRequest, description);
}
(2)具體使用方法
請求數(shù)據(jù),(兩個接口直接一定具有依賴性,這里只是舉例,其實舉例的這兩個接口沒有啥依賴)

a、請求失敗的處理

b、請求成功,UI布局

4、YTK的文件流上傳功能
我們可以通過重寫constructingBodyBlock的方法,來實現(xiàn)上傳(例如我們上傳語音和圖片),我們項目中的UploadFileAPI接口有用到
- (AFConstructingBlock)constructingBodyBlock {
return ^(id<AFMultipartFormData> formData) {
for (UploadFileModel *model in _fileModelsArray) {
[formData appendPartWithFileData:model.data name:model.fileName fileName:model.fileName mimeType:@""];
}
};
}
5、斷點續(xù)傳
要啟動斷點續(xù)傳功能,我們只需要覆蓋resumableDownloadPath方法,指定斷點續(xù)傳時文件的存儲路徑即可,文件會被自動保存到此路徑;(項目暫時沒有用到,這里現(xiàn)附上YTK的用例,假設(shè)我們需要從服務(wù)器下載一張圖片到本地)
- (NSString *)resumableDownloadPath {
NSString *libPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *cachePath = [libPath stringByAppendingPathComponent:@"Caches"];
NSString *filePath = [cachePath stringByAppendingPathComponent:_imageId];
return filePath;
}
總結(jié)
YTK隔離出了業(yè)務(wù)邏輯層,一些小的方法比較省代碼,會提高效率