iOS-網(wǎng)絡(luò)編程(三)AFNetworking使用

一. AFNetworking簡(jiǎn)單介紹

通過(guò)前面學(xué)習(xí)的HTTP協(xié)議的基本知識(shí),GET/POST請(qǐng)求的區(qū)別,NSURLConnection 和 NSURLSession的使用,已經(jīng)基本了解了網(wǎng)絡(luò)請(qǐng)求的方法,但是相對(duì)使用比較麻煩,AFNetworking是對(duì)NSURLConnection 和 NSURLSession的封裝,使網(wǎng)絡(luò)請(qǐng)求更加簡(jiǎn)單輕松,是一款非常有用的第三方框架。AFNetworking3.0以后移除了對(duì)NSURLConnection的支持。
看一下AFNetworking 歷史版本 以及框架


AFNetworking版本更新
AFNetworking框架

這些在GitHub上都可以看到,可以去GitHub上查看。

二. AFNetworking使用

1. GET請(qǐng)求

    AFHTTPSessionManager *manager =[AFHTTPSessionManager manager];
    NSDictionary *dict = @{
        @"username":@"520it",
        @"pwd":@"520it"
        };
    // parameters 參數(shù)字典
    [manager GET:@"http://120.25.226.186:32812/login" parameters:dict progress:^(NSProgress * _Nonnull downloadProgress) {
        //進(jìn)度
        //進(jìn)度
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        // task 我們可以通過(guò)task拿到響應(yīng)頭
        // responseObject:請(qǐng)求成功返回的響應(yīng)結(jié)果(AFN內(nèi)部已經(jīng)把響應(yīng)體轉(zhuǎn)換為OC對(duì)象,通常是字典或數(shù)組)
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        // error 錯(cuò)誤信息
    }];

2. POST請(qǐng)求

    AFHTTPSessionManager *manager =[AFHTTPSessionManager manager];
    NSDictionary *dict = @{
                           @"username":@"520it",
                           @"pwd":@"520it"
                           };
    [manager POST:@"http://120.25.226.186:32812/login" parameters:dict progress:^(NSProgress * _Nonnull downloadProgress) {
        // 進(jìn)度
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        // 請(qǐng)求成功
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        // 請(qǐng)求失敗
    }];

注意:我們發(fā)現(xiàn)GET和POST請(qǐng)求一模一樣,僅僅換了一個(gè)名字,GET請(qǐng)求也可以將參數(shù)放在字典中,也可以將參數(shù)拼接在url之后parameters傳nil。另外不需要開啟Task,因?yàn)锳FN內(nèi)部已經(jīng)幫我們開啟了
另外:AFN默認(rèn)會(huì)把服務(wù)器返回給我們的數(shù)據(jù)當(dāng)做是JSNO數(shù)據(jù),并且AFN內(nèi)部已經(jīng)把響應(yīng)體JSON數(shù)據(jù)轉(zhuǎn)換為OC對(duì)象,通常是字典或數(shù)組。
那么如果服務(wù)器返回的XML呢?這時(shí)我們需要自己設(shè)置AFN解析方式

manager.responseSerializer = [AFXMLParserResponseSerializer serializer];

返回的是NSXMLParser,需要我們自己解析

如果返回的數(shù)據(jù)既不是JSON也不是XML那么需要設(shè)置

manager.responseSerializer = [AFHTTPResponseSerializer serializer];

AFN默認(rèn)接收的ContentTypes 有以下三種

ContentType

如果服務(wù)器返回的ContentType不是這三種中的一種,我們就需要設(shè)置

manager.responseSerializer.acceptableContentTypes = [NSSet setWithObject:@"text/html"];

也可以直接在AFN源碼中添加(不建議使用,這種方式比較隱蔽,當(dāng)更新過(guò)AFN之后這里會(huì)還原,出現(xiàn)問題比較難找)

直接添加即可

3. 文件下載

    // 1.創(chuàng)建一個(gè)管理者
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    // 2. 創(chuàng)建請(qǐng)求對(duì)象
    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/images/minion_03.png"];
    NSURLRequest *request =[NSURLRequest requestWithURL:url];
    // 3. 下載文件
    NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:^(NSProgress * _Nonnull downloadProgress) {
    // downloadProgress.completedUnitCount 當(dāng)前下載大小
    // downloadProgress.totalUnitCount 總大小
    NSLog(@"%f", 1.0 * downloadProgress.completedUnitCount / downloadProgress.totalUnitCount);
    } destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
        // targetPath  臨時(shí)存儲(chǔ)地址
        NSLog(@"targetPath:%@",targetPath);
        NSString *path =[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
        NSString *filePath = [path stringByAppendingPathComponent:response.suggestedFilename];
        NSURL *url = [NSURL fileURLWithPath:filePath];
        NSLog(@"path:%@",filePath);
        // 返回url 我們想要存儲(chǔ)的地址
        // response 響應(yīng)頭
        return url;
    } completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
        // 下載完成之后調(diào)用
        // response 響應(yīng)頭
        // filePath 下載存儲(chǔ)地址
        NSLog(@"filePath:%@",filePath);
    }];
    // 需要手動(dòng)開啟
    [downloadTask resume];

注意:
1. 下載文件需要獲取NSURLSessionDownloadTask對(duì)象手動(dòng)開啟
2. 第一個(gè)block塊:downloadProgress 有兩個(gè)屬性completedUnitCount(已經(jīng)下載文件大?。?、totalUnitCount(文件總大?。?。
3. 第二個(gè)block塊:需要返回一個(gè)url,表示想要將文件存儲(chǔ)的地方。targetPath:表示臨時(shí)存儲(chǔ)地址在tmp臨時(shí)文件中。response:響應(yīng)頭 可以拿到一些文件信息
4. 第三個(gè)block塊:下載完成之后調(diào)用。response:響應(yīng)頭。filePath:文件存儲(chǔ)地址,與第二個(gè)block塊中返回的url是一個(gè)地址

4. 文件上傳

關(guān)于文件上傳使用AFN就簡(jiǎn)單多了,也不需要我們?nèi)テ唇诱?qǐng)求體和請(qǐng)求文件參數(shù)啦,AFN內(nèi)部已經(jīng)幫我們拼接好了
方法一:formData 添加data形式數(shù)據(jù)

    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    NSString *url =@"http://120.25.226.186:32812/upload";
    [manager POST:url parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
        // formData 將要上傳的數(shù)據(jù)
        UIImage *image =[UIImage imageNamed:@"123"];
        NSData *data =UIImagePNGRepresentation(image);
        // 方法一
        /** 
          data:上傳文件二進(jìn)制數(shù)據(jù)
          name:接口的名字
          fileName:文件上傳到服務(wù)器之后叫什么名字
          mineType:上傳文件的類型,可以上傳任意二進(jìn)制mineType.
         */
        [formData appendPartWithFileData:data name:@"file" fileName:@"123.png" mimeType:@"image/png"];
        // 方法二
        /**
         data:上傳文件二進(jìn)制數(shù)據(jù)
         name:接口的名字
         這種方法內(nèi)部會(huì)將文件名當(dāng)做上傳到服務(wù)器之后的名字,并自動(dòng)獲取其類型
         */
        [formData appendPartWithFormData:data name:@"file"];
    } progress:^(NSProgress * _Nonnull uploadProgress) {
        // 上傳進(jìn)度
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        // 上傳成功
        NSLog(@"上傳成功");
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        // 上傳失敗
        NSLog(@"上傳失敗");
    }];

方法二:formData直接添加url

    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    NSString *url =@"http://120.25.226.186:32812/upload";
    [manager POST:url parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
        // formData 將要上傳的數(shù)據(jù)
        // 直接傳URL
        NSURL *url =[NSURL fileURLWithPath:@"/Users/yangboxing/Desktop/Snip20160905_7.png"];
        // 方法一
        [formData appendPartWithFileURL:url name:@"file" fileName:@"hhaha.png" mimeType:@"image/png" error:nil];
        // 方法二
        /** 
         這個(gè)方法會(huì)自動(dòng)截取url最后一塊的文件名作為上傳到服務(wù)器的文件名 
         也會(huì)自動(dòng)獲取mimeType,如果沒有辦法獲取mimeType 就使用@"application/octet-stream" 表示任意的二進(jìn)制數(shù)據(jù) ,當(dāng)我們不在意文件類型的時(shí)候 也可以用這個(gè)。
         */
        [formData appendPartWithFileURL:url name:@"file" error:nil];
    } progress:^(NSProgress * _Nonnull uploadProgress) {
        // 上傳進(jìn)度
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        // 上傳成功
        NSLog(@"上傳成功");
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        // 上傳失敗
        NSLog(@"上傳失敗");
    }];

注意:
mimeType表示文件的類型,關(guān)于mimeType類型可以自行百度,我們也可以通過(guò)發(fā)送請(qǐng)求獲取mineType

// 通過(guò)發(fā)送請(qǐng)求獲取mimeType
-(NSString *)connectSync:(NSString *)path
{
    //1.確定請(qǐng)求路徑
    NSURL *url = [NSURL fileURLWithPath:path];
    //2.創(chuàng)建可變的請(qǐng)求對(duì)象
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    NSHTTPURLResponse *res = nil;
    [NSURLConnection sendSynchronousRequest:request returningResponse:&res error:nil];
    NSLog(@"%@",res.MIMEType);
    return res.MIMEType;
} 

我們通過(guò)[formData appendPartWithFileURL:url name:@"file" error:nil];來(lái)看看AFN是如何獲取mimeType的

文件名稱和mimeType獲取

進(jìn)入方法內(nèi)部


mimeType獲取

因此以后我們要獲取mimeType的時(shí)候也可以直接從AFN中復(fù)制拿去用嘍。

5. AFN網(wǎng)絡(luò)狀態(tài)的檢測(cè)

使用AFN進(jìn)行網(wǎng)絡(luò)狀態(tài)的檢測(cè)非常簡(jiǎn)單,并且可以持續(xù)監(jiān)聽網(wǎng)絡(luò)狀態(tài),每當(dāng)網(wǎng)絡(luò)狀態(tài)發(fā)生改變的時(shí)候,都會(huì)調(diào)用setReachabilityStatusChangeBlock方法

    AFNetworkReachabilityManager *manager = [AFNetworkReachabilityManager sharedManager];
    /*
    AFNetworkReachabilityStatusUnknown          = -1, 未知
    AFNetworkReachabilityStatusNotReachable     = 0,  沒有網(wǎng)絡(luò)
    AFNetworkReachabilityStatusReachableViaWWAN = 1,  蜂窩流量
    AFNetworkReachabilityStatusReachableViaWiFi = 2,  無(wú)線
    */
    // 監(jiān)聽網(wǎng)絡(luò)狀態(tài)的變化
    [manager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
        switch (status) {
            case AFNetworkReachabilityStatusUnknown:
                NSLog(@"未知");
                break;
            case AFNetworkReachabilityStatusNotReachable:
                NSLog(@"沒有網(wǎng)絡(luò)");
                break;
            case AFNetworkReachabilityStatusReachableViaWWAN:
                NSLog(@"3G");
                break;
            case AFNetworkReachabilityStatusReachableViaWiFi:
                NSLog(@"無(wú)線");
                break;
                
            default:
                break;
        }
    }];
    // 開啟
    [manager startMonitoring];

6. AFN向HTTPS發(fā)送請(qǐng)求。

我們知道HTTPS在HTTP的基礎(chǔ)上加入了SSL協(xié)議,SSL依靠證書來(lái)驗(yàn)證服務(wù)器的身份,并為瀏覽器和服務(wù)器之間的通信加密。
當(dāng)使用NSURLSession來(lái)向HTTPS發(fā)送請(qǐng)求時(shí),需要在NSURLSessionDataDelegate的代理方法didReceiveChallenge中,信任服務(wù)器并且創(chuàng)建證書返回服務(wù)器。
而AFN對(duì)此進(jìn)行了很好的封裝,內(nèi)部已經(jīng)幫我們做好這些,因此向HTTPS發(fā)送請(qǐng)求方法與向HTTP發(fā)送請(qǐng)求是一樣的。

我們來(lái)看AFN內(nèi)部封裝的方法

AFN內(nèi)部封裝的方法

那么當(dāng)我們用NSURLSession向HTTPS發(fā)送請(qǐng)求的時(shí)候,直接復(fù)制過(guò)來(lái)稍作修改就可以用啦

-(void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler
{
    NSLog(@"--didReceiveChallenge--%@",challenge.protectionSpace);
    /*
     NSURLSessionAuthChallengeUseCredential = 0,      使用
     NSURLSessionAuthChallengePerformDefaultHandling = 1,   忽略(默認(rèn))
     NSURLSessionAuthChallengeCancelAuthenticationChallenge = 2,忽略(會(huì)取消請(qǐng)求)
     NSURLSessionAuthChallengeRejectProtectionSpace = 3, 忽略(下次繼續(xù)詢問)
     */
    // NSURLAuthenticationMethodServerTrust 服務(wù)器信任
    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
        //創(chuàng)建證書
        NSURLCredential *credentoal = [[NSURLCredential alloc]initWithTrust:challenge.protectionSpace.serverTrust];
        completionHandler(NSURLSessionAuthChallengeUseCredential,credentoal);
    }
}

三. 總結(jié)

我們一般在使用AFN的時(shí)候會(huì)將他封裝到一個(gè)工具類中,使工具類成為一個(gè)中間層,這樣便于我們使用和對(duì)代碼的管理,以后當(dāng)AFN更新或者我們要換網(wǎng)絡(luò)請(qǐng)求第三方類庫(kù)的時(shí)候,直接更改工具類就可以了,其他類中的的網(wǎng)絡(luò)請(qǐng)求方法都不用改變,這使我們以后維護(hù)代碼更加簡(jiǎn)單快捷方便。


關(guān)于網(wǎng)絡(luò)請(qǐng)求的基礎(chǔ)知識(shí)請(qǐng)參考iOS-網(wǎng)絡(luò)編程(一)HTTP協(xié)議、iOS-網(wǎng)絡(luò)編程(二)文件上傳和斷點(diǎn)離線下載

?本文借鑒了很多前輩的文章,如果有不對(duì)的地方請(qǐng)指正,歡迎大家一起交流學(xué)習(xí) xx_cc 。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • AFURLConnectionOperation 可以說(shuō)是AFN最基礎(chǔ)的類。繼承自NSOperation類,將網(wǎng)絡(luò)...
    iOS開發(fā)攻城獅閱讀 2,138評(píng)論 0 0
  • AFN什么是AFN全稱是AFNetworking,是對(duì)NSURLConnection、NSURLSession的一...
    醉葉惜秋閱讀 1,344評(píng)論 0 0
  • 1.請(qǐng)簡(jiǎn)單說(shuō)明多線程技術(shù)的優(yōu)點(diǎn)和缺點(diǎn)? 優(yōu)點(diǎn):能夠適當(dāng)提高程序的執(zhí)行效率;能夠適當(dāng)?shù)奶岣哔Y源的利用率,比如CPU、...
    deeper_iOS閱讀 1,550評(píng)論 1 12
  • iOS開發(fā)系列--網(wǎng)絡(luò)開發(fā) 概覽 大部分應(yīng)用程序都或多或少會(huì)牽扯到網(wǎng)絡(luò)開發(fā),例如說(shuō)新浪微博、微信等,這些應(yīng)用本身可...
    lichengjin閱讀 4,040評(píng)論 2 7
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,578評(píng)論 19 139

友情鏈接更多精彩內(nèi)容