AFN框架使用

AFN框架使用

1.AFN框架基本使用

    *   NSURLSession

        *   AFURLSessionManager
        *   AFHTTPSessionManager(封裝了常用的 HTTP 方法)
            *   GET
            *   POST
            *   UIKit + AFNetworking 分類
            *   NSProgress :利用KVO
    *   半自動(dòng)的序列化&反序列化的功能

        *   AFURLRequestSerialization :請(qǐng)求的數(shù)據(jù)格式/默認(rèn)是二進(jìn)制的
        *   AFURLResponseSerialization :響應(yīng)的數(shù)據(jù)格式/默認(rèn)是JSON格式
    *   附加功能

        *   安全策略
            *   HTTPS
            *   AFSecurityPolicy
        *   網(wǎng)絡(luò)檢測(cè)
            *   對(duì)蘋果的網(wǎng)絡(luò)連接檢測(cè)做了一個(gè)封裝
            *   AFNetworkReachabilityManager

2 .AFN的基本使用

(1)發(fā)送GET請(qǐng)求的兩種方式(POST同)
 -(void)get1 {
    //1.創(chuàng)建AFHTTPRequestOperationManager管理者
    //AFHTTPRequestOperationManager內(nèi)部是基于NSURLConnection實(shí)現(xiàn)的
    AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];

    //2.發(fā)送請(qǐng)求
    /*
     http://120.25.226.186:32812/login?username=ee&pwd=ee&type=JSON
     第一個(gè)參數(shù):NSString類型的請(qǐng)求路徑,AFN內(nèi)部會(huì)自動(dòng)將該路徑包裝為一個(gè)url并創(chuàng)建請(qǐng)求對(duì)象
     第二個(gè)參數(shù):請(qǐng)求參數(shù),以字典的方式傳遞,AFN內(nèi)部會(huì)判斷當(dāng)前是POST請(qǐng)求還是GET請(qǐng)求,以選擇直接拼接還是轉(zhuǎn)換為NSData放到請(qǐng)求體中傳遞
     第三個(gè)參數(shù):請(qǐng)求成功之后回調(diào)Block
     第四個(gè)參數(shù):請(qǐng)求失敗回調(diào)Block
     */

    NSDictionary *param = @{
                            @"username":@"",
                            @"pwd":@""
                            };

    //注意:字符串中不能包含空格
    [manager GET:@"http://120.25.226.186:32812/login" parameters:param success:^(AFHTTPRequestOperation * _Nonnull operation, id  _Nonnull responseObject) {

        NSLog(@"請(qǐng)求成功---%@",responseObject);

    } failure:^(AFHTTPRequestOperation * _Nonnull operation, NSError * _Nonnull error) {
            NSLog(@"失敗---%@",error);
    }];
}

-(void)get2 {
    //1.創(chuàng)建AFHTTPSessionManager管理者
    //AFHTTPSessionManager內(nèi)部是基于NSURLSession實(shí)現(xiàn)的
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];

    //2.發(fā)送請(qǐng)求
    NSDictionary *param = @{
                            @"username":@"",
                            @"pwd":@""
                            };

    //注意:responseObject:請(qǐng)求成功返回的響應(yīng)結(jié)果(AFN內(nèi)部已經(jīng)把響應(yīng)體轉(zhuǎn)換為OC對(duì)象,通常是字典或數(shù)組)
    [manager GET:@"http://120.25.226.186:32812/login" parameters:param success:^(NSURLSessionDataTask * _Nonnull task, id  _Nonnull responseObject) {
            NSLog(@"請(qǐng)求成功---%@",[responseObject class]);

    } failure:^(NSURLSessionDataTask * _Nonnull task, NSError * _Nonnull error) {
        NSLog(@"失敗---%@",error);
    }];
}

(2)使用AFN下載文件

-(void)download {
    //1.創(chuàng)建一個(gè)管理者
    AFHTTPSessionManager *manage  = [AFHTTPSessionManager manager];

    //2.下載文件
    /*
     第一個(gè)參數(shù):請(qǐng)求對(duì)象
     第二個(gè)參數(shù):下載進(jìn)度
     第三個(gè)參數(shù):block回調(diào),需要返回一個(gè)url地址,用來(lái)告訴AFN下載文件的目標(biāo)地址
         targetPath:AFN內(nèi)部下載文件存儲(chǔ)的地址,tmp文件夾下
         response:請(qǐng)求的響應(yīng)頭
         返回值:文件應(yīng)該剪切到什么地方
     第四個(gè)參數(shù):block回調(diào),當(dāng)文件下載完成之后調(diào)用
        response:響應(yīng)頭
        filePath:文件存儲(chǔ)在沙盒的地址 == 第三個(gè)參數(shù)中block的返回值
        error:錯(cuò)誤信息
     */

    //2.1 創(chuàng)建請(qǐng)求對(duì)象
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://120.25.226.186:32812/resources/images/minion_02.png"]];

    //2.2 創(chuàng)建下載進(jìn)度,并監(jiān)聽
    NSProgress *progress = nil;

    NSURLSessionDownloadTask *downloadTask = [manage downloadTaskWithRequest:request progress:&progress destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {

        NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];

        //拼接文件全路徑
        NSString *fullpath = [caches stringByAppendingPathComponent:response.suggestedFilename];
        NSURL *filePathUrl = [NSURL fileURLWithPath:fullpath];
        return filePathUrl;

    } completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nonnull filePath, NSError * _Nonnull error) {

        NSLog(@"文件下載完畢---%@",filePath);
    }];

    //2.3 使用KVO監(jiān)聽下載進(jìn)度
    [progress addObserver:self forKeyPath:@"completedUnitCount" options:NSKeyValueObservingOptionNew context:nil];

    //3.啟動(dòng)任務(wù)
    [downloadTask resume];
}

//獲取并計(jì)算當(dāng)前文件的下載進(jìn)度
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(NSProgress *)progress change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
    NSLog(@"%zd--%zd--%f",progress.completedUnitCount,progress.totalUnitCount,1.0 * progress.completedUnitCount/progress.totalUnitCount);
}

3.AFN文件上傳

1.文件上傳拼接數(shù)據(jù)的第一種方式

[formData appendPartWithFileData:data name:@"file" fileName:@"xxoo.png" mimeType:@"application/octet-stream"];

2.文件上傳拼接數(shù)據(jù)的第二種方式

 [formData appendPartWithFileURL:fileUrl name:@"file" fileName:@"xx.png" mimeType:@"application/octet-stream" error:nil];

3.文件上傳拼接數(shù)據(jù)的第三種方式

 [formData appendPartWithFileURL:fileUrl name:@"file" error:nil];

-(void)upload {
    //1.創(chuàng)建一個(gè)請(qǐng)求管理者
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];

    //2.發(fā)送POST請(qǐng)求上傳數(shù)據(jù)
    /*
     第一個(gè)參數(shù):請(qǐng)求路徑:NSString類型
     第二個(gè)參數(shù):要上傳的非文件參數(shù)
     第三個(gè)參數(shù):block回調(diào)
        在該回調(diào)中,需要利用formData拼接即將上傳的二進(jìn)制數(shù)據(jù)
     第三個(gè)參數(shù):上傳成功的block回調(diào)
        task:dataTask(任務(wù))
        responseObject:服務(wù)器返回的數(shù)據(jù)
     第四個(gè)參數(shù):上傳失敗的block回調(diào)
        error:錯(cuò)誤信息,如果上傳文件失敗,那么error里面包含了錯(cuò)誤的描述信息
     */

    NSDictionary *dict = @{
                           @"username":@""
                           };

    [manager POST:@"http://120.25.226.186:32812/upload" parameters:dict constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {

        //把本地的圖片轉(zhuǎn)換為NSData類型的數(shù)據(jù)
        UIImage *image = [UIImage imageNamed:@"123"];
        NSData *data = UIImagePNGRepresentation(image);

        /*
         //拼接二進(jìn)制文件數(shù)據(jù)
         第一個(gè)參數(shù):要上傳的文件的二進(jìn)制數(shù)據(jù)
         第二個(gè)參數(shù):服務(wù)器接口規(guī)定的名稱
         第三個(gè)參數(shù):這個(gè)參數(shù)上傳到服務(wù)器之后用什么名字來(lái)進(jìn)行保存
         第四個(gè)參數(shù):上傳文件的MIMEType類型
         */
        [formData appendPartWithFileData:data name:@"file" fileName:@"xxoo.png" mimeType:@"application/octet-stream"];

    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nonnull responseObject) {
        NSLog(@"請(qǐng)求成功---%@",responseObject);

    } failure:^(NSURLSessionDataTask * _Nonnull task, NSError * _Nonnull error) {
        NSLog(@"請(qǐng)求失敗--%@",error);
    }];
}

-(void)upload2 {
    NSLog(@"%s",__func__);

    //1.創(chuàng)建一個(gè)請(qǐng)求管理者
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];

    //2.發(fā)送POST請(qǐng)求上傳數(shù)據(jù)
    /*
     第一個(gè)參數(shù):請(qǐng)求路徑:NSString類型
     第二個(gè)參數(shù):要上傳的非文件參數(shù)
     第三個(gè)參數(shù):block回調(diào)
     在該回調(diào)中,需要利用formData拼接即將上傳的二進(jìn)制數(shù)據(jù)
     第三個(gè)參數(shù):上傳成功的block回調(diào)
     task:dataTask(任務(wù))
     responseObject:服務(wù)器返回的數(shù)據(jù)
     第四個(gè)參數(shù):上傳失敗的block回調(diào)
     error:錯(cuò)誤信息,如果上傳文件失敗,那么error里面包含了錯(cuò)誤的描述信息
     */

    NSDictionary *dict = @{
                           @"username":@""
                           };

    [manager POST:@"http://120.25.226.186:32812/upload" parameters:dict constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {

        //本地文件的url
        NSURL *fileUrl = [NSURL fileURLWithPath:@"/Users/username/Desktop/KF[WTI`AQ3T`A@3R(B96D89.gif"];
        /*
         //拼接二進(jìn)制文件數(shù)據(jù)
         第一個(gè)參數(shù):要上傳文件的url路徑
         第二個(gè)參數(shù):服務(wù)器要求的參數(shù)名稱
         第三個(gè)參數(shù):這個(gè)文件上傳到服務(wù)器之后叫什么名稱
         第四個(gè)參數(shù):文件的mimetype類型
         第五個(gè)參數(shù):錯(cuò)誤信息
         */
//        [formData appendPartWithFileURL:fileUrl name:@"file" fileName:@"xx.png" mimeType:@"application/octet-stream" error:nil];

        //另外一種上傳文件的方式
        /*
         說(shuō)明:該方法和上面的方法等價(jià),不過(guò)該方法更加簡(jiǎn)單其內(nèi)部會(huì)自動(dòng)的的根據(jù)url路徑確定文件保存名稱,并通過(guò)內(nèi)部方法獲取上傳文件的mimetype類型
         */
        [formData appendPartWithFileURL:fileUrl name:@"file" error:nil];

    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nonnull responseObject) {
        NSLog(@"請(qǐng)求成功---%@",responseObject);

    } failure:^(NSURLSessionDataTask * _Nonnull task, NSError * _Nonnull error) {
        NSLog(@"請(qǐng)求失敗--%@",error);
    }];
}

4.使用AFN進(jìn)行序列化處理

1.AFN它內(nèi)部默認(rèn)把服務(wù)器響應(yīng)的數(shù)據(jù)當(dāng)做json來(lái)進(jìn)行解析,所以如果服務(wù)器返回給我的不是JSON數(shù)據(jù)那么請(qǐng)求報(bào)錯(cuò),這個(gè)時(shí)候需要設(shè)置AFN對(duì)響應(yīng)信息的解析方式。AFN提供了三種解析響應(yīng)信息的方式,分別是:

  • 1.AFXMLParserResponseSerializer----XML
    1. AFHTTPResponseSerializer---------默認(rèn)二進(jìn)制響應(yīng)數(shù)據(jù)
  • 3.AFJSONResponseSerializer---------JSON

*4.還有一種情況就是服務(wù)器返回給我們的數(shù)據(jù)格式不太一致(開發(fā)者工具Content-Type:text/xml),那么這種情況也有可能請(qǐng)求不成功。解決方法:
1) 直接在源代碼中修改,添加相應(yīng)的Content-Type
2) 拿到這個(gè)屬性,添加到它的集合中

-(void)serialized {
    //1.創(chuàng)建請(qǐng)求管理者,內(nèi)部基于NSURLSession
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];

    /* 知識(shí)點(diǎn)1:設(shè)置AFN采用什么樣的方式來(lái)解析服務(wù)器返回的數(shù)據(jù)*/

    //如果返回的是XML,那么告訴AFN,響應(yīng)的時(shí)候使用XML的方式解析
    manager.responseSerializer = [AFXMLParserResponseSerializer serializer];

    //如果返回的就是二進(jìn)制數(shù)據(jù),那么采用默認(rèn)二進(jìn)制的方式來(lái)解析數(shù)據(jù)
    //manager.responseSerializer = [AFHTTPResponseSerializer serializer];

    //采用JSON的方式來(lái)解析數(shù)據(jù)
    //manager.responseSerializer = [AFJSONResponseSerializer serializer];

    /* 告訴AFN,再序列化服務(wù)器返回的數(shù)據(jù)的時(shí)候,支持此種類型
    [AFJSONResponseSerializer serializer].acceptableContentTypes = [NSSet setWithObject:@"text/xml"];

    //2.把所有的請(qǐng)求參數(shù)通過(guò)字典的方式來(lái)裝載,GET方法內(nèi)部會(huì)自動(dòng)把所有的鍵值對(duì)取出以&符號(hào)拼接并最后用?符號(hào)連接在請(qǐng)求路徑后面
    NSDictionary *dict = @{
                           @"username":@"223",
                           @"pwd":@"ewr",
                           @"type":@"XML"
                           };

    //3.發(fā)送GET請(qǐng)求
    [manager GET:@"http://120.25.226.186:32812/login" parameters:dict success:^(NSURLSessionDataTask * _Nonnull task, id  _Nonnull responseObject) {

        //4.請(qǐng)求成功的回調(diào)block
        NSLog(@"%@",[responseObject class]);
    } failure:^(NSURLSessionDataTask * _Nonnull task, NSError * _Nonnull error) {

        //5.請(qǐng)求失敗的回調(diào),可以打印error的值查看錯(cuò)誤信息
        NSLog(@"%@",error);
    }];
}

4.使用AFN來(lái)檢測(cè)網(wǎng)絡(luò)狀態(tài)

可以使用AFN框架中的AFNetworkReachabilityManager來(lái)監(jiān)聽網(wǎng)絡(luò)狀態(tài)的改變,也可以利用蘋果提供的Reachability來(lái)監(jiān)聽。建議在開發(fā)中直接使用AFN框架處理。

//使用AFN框架來(lái)檢測(cè)網(wǎng)絡(luò)狀態(tài)的改變
-(void)AFNReachability {
    //1.創(chuàng)建網(wǎng)絡(luò)監(jiān)聽管理者
    AFNetworkReachabilityManager *manager = [AFNetworkReachabilityManager sharedManager];

    //2.監(jiān)聽網(wǎng)絡(luò)狀態(tài)的改變
    /*
     AFNetworkReachabilityStatusUnknown          = 未知
     AFNetworkReachabilityStatusNotReachable     = 沒(méi)有網(wǎng)絡(luò)
     AFNetworkReachabilityStatusReachableViaWWAN = 3G
     AFNetworkReachabilityStatusReachableViaWiFi = WIFI
     */
    [manager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
        switch (status) {
            case AFNetworkReachabilityStatusUnknown:
                NSLog(@"未知");
                break;
            case AFNetworkReachabilityStatusNotReachable:
                NSLog(@"沒(méi)有網(wǎng)絡(luò)");
                break;
            case AFNetworkReachabilityStatusReachableViaWWAN:
                NSLog(@"3G");
                break;
            case AFNetworkReachabilityStatusReachableViaWiFi:
                NSLog(@"WIFI");
                break;

            default:
                break;
        }
    }];

    //3.開始監(jiān)聽
    [manager startMonitoring];
}


//使用蘋果提供的Reachability來(lái)檢測(cè)網(wǎng)絡(luò)狀態(tài),如果要持續(xù)監(jiān)聽網(wǎng)絡(luò)狀態(tài)的概念,需要結(jié)合通知一起使用。

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    //1.注冊(cè)一個(gè)通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkChange) name:kReachabilityChangedNotification object:nil];

    //2.拿到一個(gè)對(duì)象,然后調(diào)用開始監(jiān)聽方法
    Reachability *r = [Reachability reachabilityForInternetConnection];
    [r startNotifier];

    //持有該對(duì)象,不要讓該對(duì)象釋放掉
    self.r = r;
}

//當(dāng)控制器釋放的時(shí)候,移除通知的監(jiān)聽
-(void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

-(void)networkChange
{
    //獲取當(dāng)前網(wǎng)絡(luò)的狀態(tài)
   if ([Reachability reachabilityForInternetConnection].currentReachabilityStatus == ReachableViaWWAN)
    {
        NSLog(@"當(dāng)前網(wǎng)絡(luò)狀態(tài)為3G");
        return;
    }

    if ([Reachability reachabilityForLocalWiFi].currentReachabilityStatus == ReachableViaWiFi)
    {
        NSLog(@"當(dāng)前網(wǎng)絡(luò)狀態(tài)為wifi");
        return;
    }

    NSLog(@"當(dāng)前沒(méi)有網(wǎng)絡(luò)");
}

5.AFN使用技巧

1.在開發(fā)的時(shí)候可以創(chuàng)建一個(gè)工具類,繼承自我們的AFN中的請(qǐng)求管理者,再控制器中真正發(fā)請(qǐng)求的代碼使用自己封裝的工具類。
2.這樣做的優(yōu)點(diǎn)是以后如果修改了底層依賴的框架,那么我們修改這個(gè)工具類就可以了,而不用再一個(gè)一個(gè)的去修改。
3.該工具類一般提供一個(gè)單例方法,在該方法中會(huì)設(shè)置一個(gè)基本的請(qǐng)求路徑。
4.該方法通常還會(huì)提供對(duì)GET或POST請(qǐng)求的封裝。
5.在外面的時(shí)候通過(guò)該工具類來(lái)發(fā)送請(qǐng)求
6.單例方法:

+ (instancetype)shareNetworkTools {
    static XMGNetworkTools *instance;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        // 注意: BaseURL中一定要以/結(jié)尾
        instance = [[self alloc] initWithBaseURL:[NSURL URLWithString:@"http://120.25.226.186:32812/"]];
    });
    return instance;
}

?著作權(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)容

  • 1.AFN框架基本使用 1 AFN內(nèi)部結(jié)構(gòu)AFN結(jié)構(gòu)體NSURLConnection(iOS9.0廢棄了)AFUR...
    smile麗語(yǔ)閱讀 3,579評(píng)論 4 46
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,670評(píng)論 4 61
  • 今天一學(xué)長(zhǎng)說(shuō)了句不經(jīng)意的話,被我拾掇了去,教育最終還是沒(méi)法產(chǎn)業(yè)化,只能掙快錢,真正的教育是走精品教育,走個(gè)性化教育...
    蛋黃麻麻L(zhǎng)amarBeane閱讀 385評(píng)論 0 1
  • 親愛的張艾婷沒(méi)事的,現(xiàn)在的努力是為了將來(lái)。忍忍就過(guò)去了,他們只是在把你教好。一切都會(huì)好起來(lái)的,加油 衣服燙不好是自...
    張艾婷閱讀 170評(píng)論 0 0

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