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

一. AFNetworking簡單介紹

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


AFNetworking版本更新
AFNetworking框架

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

二. AFNetworking使用

1. GET請求

    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) {
        //進度
        //進度
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        // task 我們可以通過task拿到響應(yīng)頭
        // responseObject:請求成功返回的響應(yīng)結(jié)果(AFN內(nèi)部已經(jīng)把響應(yīng)體轉(zhuǎn)換為OC對象,通常是字典或數(shù)組)
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        // error 錯誤信息
    }];

2. POST請求

    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) {
        // 進度
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        // 請求成功
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        // 請求失敗
    }];

注意:我們發(fā)現(xiàn)GET和POST請求一模一樣患雏,僅僅換了一個名字鹏溯,GET請求也可以將參數(shù)放在字典中,也可以將參數(shù)拼接在url之后parameters傳nil淹仑。另外不需要開啟Task丙挽,因為AFN內(nèi)部已經(jīng)幫我們開啟了
另外:AFN默認(rèn)會把服務(wù)器返回給我們的數(shù)據(jù)當(dāng)做是JSNO數(shù)據(jù)肺孵,并且AFN內(nèi)部已經(jīng)把響應(yīng)體JSON數(shù)據(jù)轉(zhuǎn)換為OC對象,通常是字典或數(shù)組颜阐。
那么如果服務(wù)器返回的XML呢平窘?這時我們需要自己設(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)更新過AFN之后這里會還原肤舞,出現(xiàn)問題比較難找)

直接添加即可

3. 文件下載

    // 1.創(chuàng)建一個管理者
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    // 2. 創(chuàng)建請求對象
    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  臨時存儲地址
        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 我們想要存儲的地址
        // response 響應(yīng)頭
        return url;
    } completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
        // 下載完成之后調(diào)用
        // response 響應(yīng)頭
        // filePath 下載存儲地址
        NSLog(@"filePath:%@",filePath);
    }];
    // 需要手動開啟
    [downloadTask resume];

注意:
1. 下載文件需要獲取NSURLSessionDownloadTask對象手動開啟
2. 第一個block塊:downloadProgress 有兩個屬性completedUnitCount(已經(jīng)下載文件大凶闲隆)、totalUnitCount(文件總大欣钇省)芒率。
3. 第二個block塊:需要返回一個url,表示想要將文件存儲的地方篙顺。targetPath:表示臨時存儲地址在tmp臨時文件中偶芍。response:響應(yīng)頭 可以拿到一些文件信息
4. 第三個block塊:下載完成之后調(diào)用。response:響應(yīng)頭德玫。filePath:文件存儲地址匪蟀,與第二個block塊中返回的url是一個地址

4. 文件上傳

關(guān)于文件上傳使用AFN就簡單多了,也不需要我們?nèi)テ唇诱埱篌w和請求文件參數(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:上傳文件二進制數(shù)據(jù)
          name:接口的名字
          fileName:文件上傳到服務(wù)器之后叫什么名字
          mineType:上傳文件的類型萄窜,可以上傳任意二進制mineType.
         */
        [formData appendPartWithFileData:data name:@"file" fileName:@"123.png" mimeType:@"image/png"];
        // 方法二
        /**
         data:上傳文件二進制數(shù)據(jù)
         name:接口的名字
         這種方法內(nèi)部會將文件名當(dāng)做上傳到服務(wù)器之后的名字,并自動獲取其類型
         */
        [formData appendPartWithFormData:data name:@"file"];
    } progress:^(NSProgress * _Nonnull uploadProgress) {
        // 上傳進度
    } 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];
        // 方法二
        /** 
         這個方法會自動截取url最后一塊的文件名作為上傳到服務(wù)器的文件名 
         也會自動獲取mimeType撒桨,如果沒有辦法獲取mimeType 就使用@"application/octet-stream" 表示任意的二進制數(shù)據(jù) 查刻,當(dāng)我們不在意文件類型的時候 也可以用這個。
         */
        [formData appendPartWithFileURL:url name:@"file" error:nil];
    } progress:^(NSProgress * _Nonnull uploadProgress) {
        // 上傳進度
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        // 上傳成功
        NSLog(@"上傳成功");
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        // 上傳失敗
        NSLog(@"上傳失敗");
    }];

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

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

我們通過[formData appendPartWithFileURL:url name:@"file" error:nil];來看看AFN是如何獲取mimeType的

文件名稱和mimeType獲取

進入方法內(nèi)部


mimeType獲取

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

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

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

    AFNetworkReachabilityManager *manager = [AFNetworkReachabilityManager sharedManager];
    /*
    AFNetworkReachabilityStatusUnknown          = -1, 未知
    AFNetworkReachabilityStatusNotReachable     = 0,  沒有網(wǎng)絡(luò)
    AFNetworkReachabilityStatusReachableViaWWAN = 1,  蜂窩流量
    AFNetworkReachabilityStatusReachableViaWiFi = 2,  無線
    */
    // 監(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(@"無線");
                break;
                
            default:
                break;
        }
    }];
    // 開啟
    [manager startMonitoring];

6. AFN向HTTPS發(fā)送請求夷磕。

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

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

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

那么當(dāng)我們用NSURLSession向HTTPS發(fā)送請求的時候荆残,直接復(fù)制過來稍作修改就可以用啦

-(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,忽略(會取消請求)
     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的時候會將他封裝到一個工具類中奴艾,使工具類成為一個中間層,這樣便于我們使用和對代碼的管理内斯,以后當(dāng)AFN更新或者我們要換網(wǎng)絡(luò)請求第三方類庫的時候蕴潦,直接更改工具類就可以了,其他類中的的網(wǎng)絡(luò)請求方法都不用改變嘿期,這使我們以后維護代碼更加簡單快捷方便品擎。


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

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末秀菱,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子蹭睡,更是在濱河造成了極大的恐慌衍菱,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,978評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件肩豁,死亡現(xiàn)場離奇詭異脊串,居然都是意外死亡,警方通過查閱死者的電腦和手機清钥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評論 2 384
  • 文/潘曉璐 我一進店門琼锋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人祟昭,你說我怎么就攤上這事缕坎。” “怎么了篡悟?”我有些...
    開封第一講書人閱讀 156,623評論 0 345
  • 文/不壞的土叔 我叫張陵谜叹,是天一觀的道長。 經(jīng)常有香客問我搬葬,道長荷腊,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,324評論 1 282
  • 正文 為了忘掉前任急凰,我火速辦了婚禮停局,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己董栽,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,390評論 5 384
  • 文/花漫 我一把揭開白布企孩。 她就那樣靜靜地躺著锭碳,像睡著了一般。 火紅的嫁衣襯著肌膚如雪勿璃。 梳的紋絲不亂的頭發(fā)上擒抛,一...
    開封第一講書人閱讀 49,741評論 1 289
  • 那天,我揣著相機與錄音补疑,去河邊找鬼歧沪。 笑死,一個胖子當(dāng)著我的面吹牛莲组,可吹牛的內(nèi)容都是我干的诊胞。 我是一名探鬼主播,決...
    沈念sama閱讀 38,892評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼锹杈,長吁一口氣:“原來是場噩夢啊……” “哼撵孤!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起竭望,我...
    開封第一講書人閱讀 37,655評論 0 266
  • 序言:老撾萬榮一對情侶失蹤邪码,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后咬清,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體闭专,經(jīng)...
    沈念sama閱讀 44,104評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年旧烧,在試婚紗的時候發(fā)現(xiàn)自己被綠了影钉。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,569評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡粪滤,死狀恐怖斧拍,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情杖小,我是刑警寧澤肆汹,帶...
    沈念sama閱讀 34,254評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站予权,受9級特大地震影響昂勉,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜扫腺,卻給世界環(huán)境...
    茶點故事閱讀 39,834評論 3 312
  • 文/蒙蒙 一岗照、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦攒至、人聲如沸厚者。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽库菲。三九已至,卻和暖如春志膀,著一層夾襖步出監(jiān)牢的瞬間熙宇,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評論 1 264
  • 我被黑心中介騙來泰國打工溉浙, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留烫止,地道東北人。 一個月前我還...
    沈念sama閱讀 46,260評論 2 360
  • 正文 我出身青樓戳稽,卻偏偏與公主長得像馆蠕,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子广鳍,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,446評論 2 348

推薦閱讀更多精彩內(nèi)容