AFNetworking 3.0以上版本的 封裝

前言

至于為什么要用AFNetworking 做APP網絡請求,我這里不copy 別人的優點了,至于為什么要封裝,用第三方的風險都知道,萬一哪天AFNetworking 的作者不跟新了,需要使用另外一款第三方網絡請求,更換也更好操作一點。

所以從綜合性能,開發便利 以及后期維護風險的角度考慮,對網絡請求層 進行 封裝是一個APP開發工作者應有的考量。

個人對AFNetworking 的偏愛,相信大多數iOS開發者 都是跟我一樣的,所以這里就基于產品開發業務需求的角度,做了一個封裝。

產品需求

  • 提供基本的請求傳入參數接口,比如請求的ViewController,請求的地址等等
  • 提供基本的請求回掉,使用 block 回掉,必須的有錯誤回掉,請求成功的回掉,還可以根據自己實際需求 回掉 statusCode等等內容
  • 判斷當前網絡狀態,如果無網絡狀態,直接返回錯誤回掉。
  • 這些方法返回值 最好為 NSURLSessionDataTask,方便對這個網絡請求做相關的取消操作。
  • 對于 GET 類請求,如果請求成功,增加緩存策略

基本實現

創建一個MyBaseNetWorking文件,繼承NSObject即可,
引入頭文件 AFNetworkActivityIndicatorManager.h AFNetworking.h

step 1 準備工作 網絡狀態的判斷

我建議大家 在AppDelegate 中直接加入這個判斷,并創建一個單例Model->MyAppConfigModel,記錄APP的網絡狀態,這個會非常有用。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    /*********** AFNetworkActivityIndicatorManager 所有通過AF發送的請求, 都會在電池條上出現圓圈提示  ***********/
    [AFNetworkActivityIndicatorManager sharedManager].enabled = YES;
    /***********  監聽當前網絡狀態    *************/
    [[AFNetworkReachabilityManager sharedManager] setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
        NSLog(@"當前網絡狀態: %@", AFStringFromNetworkReachabilityStatus(status));
    }];
    // 開始監測網絡狀態
    [[AFNetworkReachabilityManager sharedManager] startMonitoring];
    
    [self configReachabilityStatusByAFNetwork];
}

/**
 監測網絡類型
 */
-(void)configReachabilityStatusByAFNetwork {
    AFNetworkReachabilityManager *manager = [AFNetworkReachabilityManager sharedManager];
    [manager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
       // 用單例model 記錄網絡狀態,這樣可以在APP任何地方調用這個熟悉 都可以得到當前網絡狀態。
 [MyAppConfigModel sharedSingleton].netWorkReachabilityStatus = status;
        switch (status) {
            case AFNetworkReachabilityStatusUnknown:
                NSLog(@"當前網絡:未知");
                break;
            case AFNetworkReachabilityStatusNotReachable:
                NSLog(@"當前網絡:網絡無連接\n請檢查網絡");
                break;
            case AFNetworkReachabilityStatusReachableViaWWAN:
                NSLog(@"當前網絡:3G|4G");
                break;
            case AFNetworkReachabilityStatusReachableViaWiFi:
                NSLog(@"當前網絡:WiFi");
                break;
            default:
                break;
        }
    }];
}

step 2 緩存策略

我這里就使用非常簡單的NSKeyedArchiver
寫操作:


if (cache == YES) {
    NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObjectInArr];
    NSString *cachePath = [docPath stringByAppendingPathComponent:task.currentRequest.URL.absoluteString.MD5];
    [[NSOperationQueue new] addOperationWithBlock:^{
         [NSKeyedArchiver archiveRootObject:responseObject toFile:cachePath];
    }];
}

讀操作:

//如果需要緩存 讀取緩存
 if (cache == YES) {
     NSString *cachePath = [docPath stringByAppendingPathComponent:task.currentRequest.URL.absoluteString.MD5];
     id responseObj = [NSKeyedUnarchiver unarchiveObjectWithFile:cachePath];
            NSLog(@" 讀取緩存  get 失敗 url = %@ \n statusCode =%ld",url,(long)responses.statusCode);
             [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                if (responseObj) {
                !completionHandler ?: completionHandler(responseObj, nil,(long)responses.statusCode);
               }else{
              !completionHandler ?: completionHandler(nil, error, (long)responses.statusCode);
           }
      }];
}

step 3 設置AFHTTPSessionManager對象,配置統一屬性

MyBaseNetWorking.m文件中

+ (AFHTTPSessionManager *)manager {
    [AFNetworkActivityIndicatorManager sharedManager].enabled = YES;
    
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    //默認解析模式
    manager.requestSerializer = [AFHTTPRequestSerializer serializer];
    manager.responseSerializer = [AFJSONResponseSerializer serializer];
    
    //配置請求序列化
    AFJSONResponseSerializer *serializer = [AFJSONResponseSerializer serializer];
    [serializer setRemovesKeysWithNullValues:YES];
    manager.requestSerializer.stringEncoding = NSUTF8StringEncoding;
    //配置響應序列化
    manager.responseSerializer.acceptableContentTypes = [NSSet setWithArray:@[@"application/json",
                                                                              @"text/html",
                                                                              @"text/json",
                                                                              @"text/plain",
                                                                              @"text/javascript",
                                                                              @"text/xml",
                                                                              @"image/*",
                                                                              @"application/octet-stream",
                                                                              @"application/zip"]];
    //請求時間
    manager.requestSerializer.timeoutInterval = 15.f;

    //設置請求頭 舉例
    NSString *userID = [NSString stringWithFormat:@"%@",[kUserDefaults valueForKey:@"UserID"]];
    [manager.requestSerializer setValue:[kUserDefaults valueForKey:@"Authorization"] forHTTPHeaderField:@"Authorization"];
    [manager.requestSerializer setValue:userID forHTTPHeaderField:@"UserID"];
    
    return manager;
}

step 4 設置AFHTTPSessionManager對象,配置統一屬性

MyBaseNetWorking.h 文件中 設計自己的 API 接口


封裝 GET 請求
MyBaseNetWorking.h文件中

/**
 get 網絡請求
 @param path 路徑 不要Base路徑
 @param controller 網絡請求所在的控制器
 @param cache 是否需要緩存
 @param parameters 參數
 @param completionHandler 處理事件
 @return 返回NSURLSessionDataTask對象
 */
+ (id)setGET:(NSString *)path controller:(UIViewController *)controller cache:(BOOL)cache parameters:(NSDictionary *)parameters completionHandler:(void(^)(id responseObj, NSError *error,NSInteger statusCode))completionHandler;

MyBaseNetWorking.m文件中實現

/********************        實現方法   **********************/
+(id)setGET:(NSString *)path controller:(UIViewController *)controller cache:(BOOL)cache parameters:(NSDictionary *)parameters completionHandler:(void (^)(id, NSError *, NSInteger))completionHandler{
    kDefineWeakSelf;
    AFHTTPSessionManager *manager = [self manager];
    NSString *url = [NSString stringWithFormat:@"%@%@",BaseHttpsURL,path];
    NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObjectInArr];
    NSString *encodedPath = [path stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    
    NSURLSessionDataTask *task = nil;
    
// 無網絡狀態
    if ([MyAppConfigModel sharedSingleton].netWorkReachabilityStatus == AFNetworkReachabilityStatusNotReachable) {
        NSError *err = [NSError errorWithDomain:@"ErrorDomain" code:-999 userInfo:[NSDictionary dictionaryWithObject:@"網絡出現錯誤,請檢查網絡連接" forKey:NSLocalizedDescriptionKey]];
        !completionHandler ?: completionHandler(nil, err, -999);
        return task;
    }
    
    task= [manager GET:encodedPath parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        NSHTTPURLResponse * responses = (NSHTTPURLResponse *)task.response;
        NSLog(@" get 請求成功 statusCode  = %ld  \n url=%@  \n responseObject = %@ ",(long)responses.statusCode,url,responseObject);
        //如果需要緩存
        
        if (cache == YES) {
            NSString *cachePath = [docPath stringByAppendingPathComponent:task.currentRequest.URL.absoluteString.MD5];
            [[NSOperationQueue new] addOperationWithBlock:^{
                [NSKeyedArchiver archiveRootObject:responseObject toFile:cachePath];
            }];
        }
        !completionHandler?:completionHandler(responseObject, nil,(long)responses.statusCode);
        
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        [[NSOperationQueue new] addOperationWithBlock:^{
            NSHTTPURLResponse * responses = (NSHTTPURLResponse *)task.response;
                //如果需要緩存 讀取緩存
                if (cache == YES) {
                    NSString *cachePath = [docPath stringByAppendingPathComponent:task.currentRequest.URL.absoluteString.MD5];
                    id responseObj = [NSKeyedUnarchiver unarchiveObjectWithFile:cachePath];
                    NSLog(@" 讀取緩存  get 失敗 url = %@ \n statusCode =%ld",url,(long)responses.statusCode);
                    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                        if (responseObj) {
                            NSLog(@" 有緩存 ");
                            !completionHandler ?: completionHandler(responseObj, nil,(long)responses.statusCode);
                        }else{
                            NSLog(@" 緩存 nil");
                            !completionHandler ?: completionHandler(nil, error, (long)responses.statusCode);
                        }
                    }];
                }else{
                    NSLog(@" 無緩存  get 失敗 url = %@ \n statusCode =%ld",url,(long)responses.statusCode);
                    !completionHandler ?: completionHandler(nil, error, (long)responses.statusCode);
                }
        }];
    }];
    return task;
}

封裝 POST 請求
MyBaseNetWorking.h文件中

/**
 post 網絡請求
 
 @param path 路徑 不要Base路徑
 @param controller 網絡請求所在的控制器
 @param parameters 參數
 @param completionHandler 處理事件
 @return 返回NSURLSessionDataTask對象
 */
+ (id)setPOST:(NSString *)path controller:(UIViewController *)controller parameters:(NSDictionary *)parameters completionHandler:(void(^)(id responseObj, NSError *error,NSInteger statusCode))completionHandler;

MyBaseNetWorking.m文件中實現


+(id)setPOST:(NSString *)path controller:(UIViewController *)controller parameters:(NSDictionary *)parameters completionHandler:(void (^)(id, NSError *, NSInteger))completionHandler{
    kDefineWeakSelf;
    
    AFHTTPSessionManager *manager = [self manager];
    
    NSString *url = [NSString stringWithFormat:@"%@%@",BaseHttpsURL,path];
    
    
    NSURLSessionDataTask *task = nil;
    
    if ([MyAppConfigModel sharedSingleton].netWorkReachabilityStatus == AFNetworkReachabilityStatusNotReachable) {
        NSError *err = [NSError errorWithDomain:@"ErrorDomain" code:-999 userInfo:[NSDictionary dictionaryWithObject:@"網絡出現錯誤,請檢查網絡連接" forKey:NSLocalizedDescriptionKey]];
        !completionHandler ?: completionHandler(nil, err, -999);
        return task;
    }
    
    task = [manager POST:url parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        NSHTTPURLResponse * responses = (NSHTTPURLResponse *)task.response;
        NSLog(@" Post url =%@ statusCode  =%ld  \n成功 \n responseObject = %@ ",url,(long)responses.statusCode,responseObject);
        !completionHandler?:completionHandler(responseObject, nil,(long)responses.statusCode);
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        [[NSOperationQueue new] addOperationWithBlock:^{
            NSHTTPURLResponse * responses = (NSHTTPURLResponse *)task.response;
                        !completionHandler ?: completionHandler(nil, error,responses.statusCode);
                    }
                }];
            }else{
                NSLog(@" POST 失敗 url = %@ statusCode= %ld \n error = %@ ",url,(long)responses.statusCode,error);
                !completionHandler ?: completionHandler(nil, error, (long)responses.statusCode);
        }];
    }];
    return task;
}

封裝 取消 請求
MyBaseNetWorking.h文件

/**
 取消指定網絡請求任務。
 @param task 指定的網絡請求任務
 */
+ (void)cancleNSURLSessionTask:(NSURLSessionTask *)task;

MyBaseNetWorking.m文件中實現

+(void)cancleNSURLSessionTask:(NSURLSessionTask *)task{
    [task cancel];
}

至此 AFNetworking 基本封裝完畢

如何使用?

在控制器可以創建一個對象NSURLSessionDataTask *netWorkingTask

-(void)netWorking{
    [self.view showNetWorkingLoadingWithInfo:@"加載中..."];
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        self.netWorkingTask =  [MyNormalNetWorking getHistroyCarNoListController:self completionHandler:^(id responseObj, NSError *error, NSInteger statusCode) {
            dispatch_async(dispatch_get_main_queue(), ^{
                if (error) {
                    [self.view showErrorWithInfo:@"請求失敗"];
                    NSLog(@"error = %@",error);
                }else{
                    [self.view showDarkTextColorToastInfo:@"請求成功" userInteractionEnabled:NO];
                    self.textView.text  = [NSString stringWithFormat:@"%@",responseObj];
                }
            });
        }];
    });
}

// 以下方法是 繼承 了MyBaseNetWorking創建的一個統一管理請求的基礎類MyNormalNetWorking
+ (id)getHistroyCarNoListController:(UIViewController *)controller completionHandler:(void (^)(id , NSError *, NSInteger))completionHandler{
   NSString *path = @"http://192.168.20.70:8080/parkingService/userCarNo/getHistoryCarNo.action?userId=utopa&limit=6";
    return [self setGET:path controller:controller cache:YES parameters:nil completionHandler:^(id responseObj, NSError *error, NSInteger statusCode) {
        !completionHandler ?: completionHandler(responseObj ,error, statusCode);
    }];
}

// 取消網絡請求
 [MyNormalNetWorking cancleNSURLSessionTask:self.netWorkingTask];

如有建議,請留言。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,431評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,637評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,555評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,900評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,629評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,976評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,976評論 3 448
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,139評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,686評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,411評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,641評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,129評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,820評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,233評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,567評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,362評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,604評論 2 380

推薦閱讀更多精彩內容