原始粗狂版本
CTNetworking 源碼分析
從最外部的業(yè)務(wù)層開始,一步一步的向底層分析
demo 中FireSingleAPI 類作為業(yè)務(wù)層網(wǎng)絡(luò)請求的入口
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
//開始網(wǎng)絡(luò)請求
[self.testAPIManager loadData];
}
//進行網(wǎng)絡(luò)請求的類
- (TestAPIManager *)testAPIManager
{
if (_testAPIManager == nil) {
_testAPIManager = [[TestAPIManager alloc] init];
//網(wǎng)絡(luò)請求結(jié)果回調(diào)
_testAPIManager.delegate = self;
//網(wǎng)絡(luò)請求參數(shù)代理
_testAPIManager.paramSource = self;
}
return _testAPIManager;
}
//設(shè)置網(wǎng)絡(luò)請求參數(shù)的代理
pragma mark - CTAPIManagerParamSource
-
(NSDictionary *)paramsForApi:(CTAPIBaseManager *)manager
{
NSDictionary *params = @{};if (manager == self.testAPIManager) {
params = @{
kTestAPIManagerParamsKeyLatitude:@(31.228000),
kTestAPIManagerParamsKeyLongitude:@(121.454290)
};
}
return params;
}
//網(wǎng)絡(luò)請求結(jié)果代理
pragma mark - CTAPIManagerCallBackDelegate
//請求成功
- (void)managerCallAPIDidSuccess:(CTAPIBaseManager *)manager
{
if (manager == self.testAPIManager) {
self.resultLable.text = @"success";
NSLog(@"%@", [manager fetchDataWithReformer:nil]);
[self layoutResultLable];
}
}
//請求失敗
- (void)managerCallAPIDidFailed:(CTAPIBaseManager *)manager
{
if (manager == self.testAPIManager) {
self.resultLable.text = @"fail";
NSLog(@"%@", [manager fetchDataWithReformer:nil]);
[self layoutResultLable];
}
}
以上就是業(yè)務(wù)層關(guān)于CTNetworking 網(wǎng)絡(luò)框架的用法。
使用 TestAPIManager 進行網(wǎng)絡(luò)請求, 設(shè)置請求參數(shù), 獲取請求結(jié)果
TestAPIManager 類
這里詳細看一下 TestAPIManager 是如何進行網(wǎng)絡(luò)請求, 設(shè)置請求參數(shù) 處理請求結(jié)果的
從loadData 開始
- (NSInteger)loadData
{
//獲取請求參數(shù), self.paramSource 的代理一般都是進行網(wǎng)絡(luò)請求的業(yè)務(wù)層類 上面我們已經(jīng)設(shè)置了請求參數(shù),這里直接獲取
NSDictionary *params = [self.paramSource paramsForApi:self];
//進行網(wǎng)絡(luò)請求
NSInteger requestId = [self loadDataWithParams:params];
return requestId;
}
查看loadDataWithParams 方法
這個方法,詳細處理了網(wǎng)絡(luò)請求的具體操作
- 網(wǎng)絡(luò)請求是否會被攔截,這里出現(xiàn)了網(wǎng)絡(luò)攔截器 的類 CTAPIManagerInterceptor
使用網(wǎng)絡(luò)攔截器來 判斷網(wǎng)絡(luò)請求參數(shù)是否合法,合法則繼續(xù)網(wǎng)絡(luò)請求,非法則攔截網(wǎng)絡(luò)請求 - 查看是否有緩存,如果有緩存 則不進行網(wǎng)絡(luò)請求直接 取本地緩存的數(shù)據(jù)
- 沒有本地緩存則從服務(wù)器請求數(shù)據(jù)
-
(NSInteger)loadDataWithParams:(NSDictionary *)params
{NSInteger requestId = 0;
NSDictionary *apiParams = [self reformParams:params];
if ([self shouldCallAPIWithParams:apiParams]) {
//判斷請求參數(shù)是否合法
if ([self.validator manager:self isCorrectWithParamsData:apiParams]) {
// shouldLoadFromNative 在TestAPIManager中并沒有實現(xiàn), 而是在TestAPIManager的父類CTAPIBaseManager 中實現(xiàn)了該方法,其實當(dāng) 程序走到這里是 self就是TestAPIManager,
//所以把shouldLoadFromNative 實現(xiàn)在TestAPIManager 類中和實現(xiàn)在CTAPIBaseManager類中原理是一樣的,此時TestAPIManager 就是CTAPIBaseManager 類
if ([self.child shouldLoadFromNative]) {//是否加載 本地緩存數(shù)據(jù)
[self loadDataFromNative];
}// 先檢查一下是否從本篤獲取緩存數(shù)據(jù) if ([self shouldCache] && [self hasCacheWithParams:apiParams]) { return 0; } // 從服務(wù)器獲取數(shù)據(jù) if ([self isReachable]) {//檢查是否聯(lián)網(wǎng),網(wǎng)絡(luò)狀態(tài) self.isLoading = YES;//開啟加載狀態(tài) switch (self.child.requestType) { //GET case CTAPIManagerRequestTypeGet: AXCallAPI(GET, requestId); break; //POST case CTAPIManagerRequestTypePost: AXCallAPI(POST, requestId); break; //PUT case CTAPIManagerRequestTypePut: AXCallAPI(PUT, requestId); break; //DELETE case CTAPIManagerRequestTypeDelete: AXCallAPI(DELETE, requestId); break; default: break; } NSMutableDictionary *params = [apiParams mutableCopy]; params[kCTAPIBaseManagerRequestID] = @(requestId); [self afterCallingAPIWithParams:params]; return requestId; } else { [self failedOnCallingAPI:nil withErrorType:CTAPIManagerErrorTypeNoNetWork]; return requestId; } } else { [self failedOnCallingAPI:nil withErrorType:CTAPIManagerErrorTypeParamsError]; return requestId; }}
return requestId;
}
我們先從服務(wù)器請求數(shù)據(jù)開始,加載本地緩存 后面再分析
當(dāng)網(wǎng)絡(luò)請求成功之后,會調(diào)用方法:successedOnCallingAPI
主要處理事項:
- 驗證網(wǎng)絡(luò)數(shù)據(jù)是否合法
- 將網(wǎng)絡(luò)數(shù)據(jù)緩存到本地 用CTCachedObject 類去緩存數(shù)據(jù)
- 響應(yīng)成功 通知代理(業(yè)務(wù)層)去將網(wǎng)絡(luò)數(shù)據(jù)更新到UI
- 響應(yīng)的數(shù)據(jù)出錯 通知代理(業(yè)務(wù)層) 讓UI做失敗處理
-
(void)successedOnCallingAPI:(CTURLResponse *)response
{
//網(wǎng)絡(luò)等待狀態(tài)
self.isLoading = NO;
self.response = response;
//是否從本地加載
if ([self.child shouldLoadFromNative]) {
if (response.isCache == NO) {
//將響應(yīng)數(shù)據(jù) 保存到本地
[[NSUserDefaults standardUserDefaults] setObject:response.responseData forKey:[self.child methodName]];
[[NSUserDefaults standardUserDefaults] synchronize];
}
}
//將響應(yīng)數(shù)據(jù) 賦值給 self
if (response.content) {
self.fetchedRawData = [response.content copy];
} else {
self.fetchedRawData = [response.responseData copy];
}
//把 response 從響應(yīng)隊列中刪除
[self removeRequestIdWithRequestID:response.requestId];
//驗證返回 數(shù)據(jù)的參數(shù)是否正確
if ([self.validator manager:self isCorrectWithCallBackData:response.content]) {//正確
//緩存 請求到的數(shù)據(jù)
if ([self shouldCache] && !response.isCache) {
[self.cache saveCacheWithData:response.responseData serviceIdentifier:self.child.serviceType methodName:self.child.methodName requestParams:response.requestParams];
}if ([self beforePerformSuccessWithResponse:response]) { if ([self.child shouldLoadFromNative]) {//是否從加載本地緩存 if (response.isCache == YES) {//緩存的response //業(yè)務(wù)層 處理響應(yīng)數(shù)據(jù) [self.delegate managerCallAPIDidSuccess:self]; } if (self.isNativeDataEmpty) {//本地緩存為空 //業(yè)務(wù)層 處理響應(yīng)數(shù)據(jù) [self.delegate managerCallAPIDidSuccess:self]; } } else { //業(yè)務(wù)層 處理響應(yīng)數(shù)據(jù) [self.delegate managerCallAPIDidSuccess:self]; } } //獲取到響應(yīng)數(shù)據(jù)之后的處理 [self afterPerformSuccessWithResponse:response];} else {
//響應(yīng)數(shù)據(jù) 不正確
[self failedOnCallingAPI:response withErrorType:CTAPIManagerErrorTypeNoContent];
//CTAPIManagerErrorTypeNoContent API請求成功但返回數(shù)據(jù)不正確。如果回調(diào)數(shù)據(jù)驗證函數(shù)返回值為NO,manager的狀態(tài)就會是這個
}
}
上面的方法是響應(yīng)數(shù)據(jù)成功后的處理
現(xiàn)在分享響應(yīng)數(shù)據(jù)失敗之后的處理
方法:failedOnCallingAPI
主要處理事項:
根據(jù)不同的錯誤類型 做不同的處理
1.token 過期
2.token 無效
3.無權(quán)限
4.其他錯誤
方法如下:
//針對不同響應(yīng)數(shù)據(jù)失敗類型 分別處理
- (void)failedOnCallingAPI:(CTURLResponse *)response withErrorType:(CTAPIManagerErrorType)errorType
{
self.isLoading = NO;//加載狀態(tài)為 NO
self.response = response;
if ([response.content[@"id"] isEqualToString:@"expired_access_token"]) {
// token 過期
//發(fā)送 token 過期通知
[[NSNotificationCenter defaultCenter] postNotificationName:kBSUserTokenInvalidNotification
object:nil
userInfo:@{
kBSUserTokenNotificationUserInfoKeyRequestToContinue:[response.request mutableCopy],
kBSUserTokenNotificationUserInfoKeyManagerToContinue:self
}];
} else if ([response.content[@"id"] isEqualToString:@"illegal_access_token"]) {
// token 無效,重新登錄
[[NSNotificationCenter defaultCenter] postNotificationName:kBSUserTokenIllegalNotification
object:nil
userInfo:@{
kBSUserTokenNotificationUserInfoKeyRequestToContinue:[response.request mutableCopy],
kBSUserTokenNotificationUserInfoKeyManagerToContinue:self
}];
} else if ([response.content[@"id"] isEqualToString:@"no_permission_for_this_api"]) {
//非法權(quán)限
[[NSNotificationCenter defaultCenter] postNotificationName:kBSUserTokenIllegalNotification
object:nil
userInfo:@{
kBSUserTokenNotificationUserInfoKeyRequestToContinue:[response.request mutableCopy],
kBSUserTokenNotificationUserInfoKeyManagerToContinue:self
}];
} else {
// 其他錯誤
self.errorType = errorType;
//在響應(yīng)列表中刪除 該響應(yīng)事件
[self removeRequestIdWithRequestID:response.requestId];
if ([self beforePerformFailWithResponse:response]) {
// 業(yè)務(wù)層回調(diào) 請求響應(yīng)數(shù)據(jù)失敗方法
[self.delegate managerCallAPIDidFailed:self];
}
[self afterPerformFailWithResponse:response];
}
}
CTAPIBaseManager 類就分析到這
比較兩個方法是否相等:
如果遇到兩個同名的方法,怎么樣才能判斷他們是同一個方法呢?
如下:
IMP childIMP = [self.child methodForSelector:@selector(reformParams:)];//代理方法
IMP selfIMP = [self methodForSelector:@selector(reformParams:)];//自身方法
if (childIMP == selfIMP) {//判斷是否是同一個方法
return params;
}
如何處理緩存。
創(chuàng)建緩存對象CTCachedObject ,對象的屬性有 緩存內(nèi)容,緩存是否為空,緩存是否過期,緩存跟新時間
方法有:帶有緩存內(nèi)容的初始化方法, 更新緩存內(nèi)容的方法
緩存的保存,獲取,刪除等操作, 把這些操作抽象成一個對象 CTCache 。
考慮到 緩存到處都在使用,把他設(shè)為單類。
他有一個 NSCache 對象,可以對 緩存對象CTCachedObject進行增刪改的操作。