AFNetwork 3.x 在开发中常用基础的介绍

版权声明:本文为博主原创文章,未经博主允许不得转载。

从iOS 7 和 Mac OS X 10.9 Mavericks 开始,苹果一个显著的变化就是对 Foundation URL 加载系统的彻底重构。所以现在 AFN 3.x版本完全摒弃了NSURLConnection,而使用了基于NSURLSession的下载方式。

要讲什么


  • 1、AFNetworking的基本使用
  • 2、AFNetworking上传文件
  • 3、AFNetworking下载文件
  • 4、AFNetworking的序列化
  • 5、AFNetworking使用小技巧
  • 6、AFNetworking的附加Category使用

开始讲了


1、AFNetworking的基本使用

  • 创建会话管理者,使用AFHTTPSessionManager创建,不是使用AFURLSessionManager,因为AFURLSessionManager没有manager方法,两者之间是继承的关系,HTTP请求几乎都是由AFURLSessionManager这个类发起。

  • 开始GET请求,举个栗子:

  - (void)GET:(NSString *)URLString parameters:(id)parameters progress:(void (^)(CGFloat))downloadProgress success:(void (^)(id))success failure:(void (^)(NSError *))failure {
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    [manager GET:URLString parameters:parameters progress:^(NSProgress * _Nonnull progress) {
        if (downloadProgress) {
            downloadProgress(progress.completedUnitCount / progress.totalUnitCount);
        }
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        success(responseObject);
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        failure(error);
    }];
}
  • 开始POST请求,也举个栗子:
  - (void)POST:(NSString *)URLString parameters:(id)parameters success:(void (^)(id))success failure:(void (^)(NSError *))failure {
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    [manager POST:@"qiyoukeji.com/IMHttpJsonServlet" parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        success(responseObject);
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        failure(error);
    }];
}

2、AFNetworking上传文件

  • Multipart是HTTP协议为web表单新增的上传文件的协议,AFURLRequestSerialization一半以上的代码都是在构建Multipart请求。

  • 如何构造Multipart里的数据?
    a. 直接把文件所有内容读取出来,再按上述协议加上头部和分隔符,拼接好数据后扔给NSURLRequest的body。但这样做是不可用的,因为文件可能很大,这样拼数据把整个文件读进内存,很可能把内存撑爆了。

b. 不把文件读出来,不在内存拼,而是新建一个临时文件,在这个文件上拼接数据,再把文件地址扔给NSURLRequest的bodyStream,这样上传的时候是分片读取这个文件,不会撑爆内存,但这样每次上传都需要新建个临时文件,对这个临时文件的管理很挺麻烦。

c. 构建自己的数据结构,只保存要上传的文件地址,边上传边拼数据,上传是分片的,拼数据也是分片的,拼到文件实体部分时直接从原来的文件分片读取。这方法没上述两种的问题,只是实现起来也没上述两种简单。

  • 开始上传文件,继续来举栗子:
  - (void)POST:(NSString *)URLString parameters:(id)parameters data:(NSData *)data mimeType:(NSString *)mimeType fileName:(NSString *)fileName success:(void (^)(id))success progress:(void (^)(CGFloat))uploadProgress failure:(void (^)(NSError *))failure {
    [self.httpRequestManager POST:@"qiyoukeji.com/IMHttpJsonServlet" parameters:parameters constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
        
        [formData appendPartWithFileData:data name:@"dataFile" fileName:fileName mimeType:mimeType];
//        [formData appendPartWithFileURL:[NSURL URLWithString:@"localPath"] name:@"name" fileName:@"fileName" mimeType:mimeType error:nil];
//        [formData appendPartWithInputStream:nil name:@"name" fileName:@"fileName" length:10000 mimeType:mimeType];
        
    } progress:^(NSProgress * _Nonnull progress) {
        if (uploadProgress) {
            uploadProgress(1.0 * progress.completedUnitCount / progress.totalUnitCount);
        }
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        success(responseObject);
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        failure(error);
    }];
}

这里用一个AFStreamingMultipartFormData对象(实现了AFMultipartFormData协议),调不同的append方法就可以添加不同类型数据,包括FileURL/NSData/NSInputStreamAFStreamingMultipartFormData内部把这些append的数据转成不同类型的AFHTTPBodyPart,添加到自定义的AFMultipartBodyStream里,最后把AFMultipartBodyStream赋给原来NSMutableURLRequestbodyStream

AFMultipartBodyStream封装了整个multipart数据的读取,主要是根据读取的位置确定现在要读哪一个AFHTTPBodyPartAFStreamingMultipartFormData对外提供友好的append接口,并把构造好的AFMultipartBodyStream赋回给NSMutableURLRequest,关系大致如下图:

AFURLRequestSerialization.png

3、AFNetworking下载文件

  • 开始下载文件(支持断点下载),还是举栗子:
  - (void)POST:(NSString *)URLString parameters:(id)parameters bytesRange:(NSRange)bytesRange progress:(void (^)(CGFloat))downloadProgress success:(void (^)(id))success failure:(void (^)(NSError *))failure {
    NSMutableURLRequest *downloadRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:URLString]];
    [downloadRequest setValue:@"Range" forHTTPHeaderField:[NSString stringWithFormat:@"bytes=%lu-%@", bytesRange.location, 0 == bytesRange.length ? @"" : [NSString stringWithFormat:@"%lu", (bytesRange.location + bytesRange.length)]]];
    
    [self.httpRequestManager downloadTaskWithRequest:downloadRequest progress:^(NSProgress * _Nonnull progress) {
        if (downloadProgress) {
            downloadProgress(progress.completedUnitCount / progress.totalUnitCount);
        }
    } destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
        // 默认下载地址
        DDLogInfo(@"targetPath = %@",targetPath);
        
        NSString *filePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
        return [NSURL URLWithString:filePath];
    } completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
        if (!error) {
            success(filePath);
        } else {
            failure(error);
        }
    }];
}
*  bytesRange是分段下载时的临时文件大小;
*  downloadProgress是下载进度,由`completedUnitCount` / `totalUnitCount`计算而来;

4、AFNetworking的序列化

  • AFNetworking响应请求和响应结果解析都是有自成一套的序列化操作,主要由AFURLRequestSerializationAFURLResponseSerialization完成,其中AFURLRequestSerialization的默认序列化方式是AFHTTPRequestSerializerAFURLResponseSerialization的默认序列化方式是AFJSONResponseSerializer
请求格式:
 AFHTTPRequestSerializer              二进制格式
 AFJSONRequestSerializer              JSON
 AFPropertyListRequestSerializer      PList(是一种特殊的XML)

返回格式:
 AFHTTPResponseSerializer             二进制格式
 AFJSONResponseSerializer             JSON
 AFXMLParserResponseSerializer        XML,只能返回XMLParser,还需要自己通过代理方法解析
 AFXMLDocumentResponseSerializer     (Mac OS X)
 AFPropertyListResponseSerializer     PList
 AFImageResponseSerializer            Image
 AFCompoundResponseSerializer         组合
  • 常见的Content-Type返回类型报错的问题分析
问题:  unacceptable content-type: text/plain
          { status code: 200, headers {
            "Content-Length" = 14;
            "Content-Type" = "text/plain;charset=utf-8";
            Date = "Thu, 22 May 2014 10:37:50 GMT";
            Server = "Apache-Coyote/1.1";
           "Set-Cookie" ="JSESSIONID=C0DFED60A154557F8386E62AB2A066CE; Path=/FHJRDT";
          } }, NSLocalizedDescription=Request failed:unacceptable content-type: text/plain}

          如果接口返回的 Content-Type 和实际情况不合时,有时候是因为后端开发人员不规范导致,如果为了统一返回值,可以使用[NSJSONSerialization  JSONObjectWithData:data options:0 error:nil]处理,否则需要根据项目中的不规范的HTTP返回做自己的处理

5、AFNetworking使用小技巧

  • 项目在构建的时候一定会有很多的ViewController,那么对于底层网络交互的实现方式其实上层时并不关心的,所以在使用AFNetwoeking时,建议自己在其外层做一层自己的封装,更能在需要替换网络请求实现体的时候,几乎不用更改项目UI层代码,降低耦合性。

  • 还是来张图吧:


    Help.png

6、AFNetworking的附加Category使用

  • AFNetworkActivityIndicatorManager.h,可以控制HTTP请求时是否显示网络等待小菊花,[[AFNetworkActivityIndicatorManager sharedManager] setEnabled:YES];;
/**
 A Boolean value indicating whether the manager is enabled.

 If YES, the manager will change status bar network activity indicator according to ;network operation notifications it receives. The default value is NO.
 */
@property (nonatomic, assign, getter = isEnabled) BOOL enabled;

/**
A Boolean value indicating whether the network activity indicator manager is currently active.
*/
@property (readonly, nonatomic, assign, getter=isNetworkActivityIndicatorVisible) BOOL networkActivityIndicatorVisible;
  • UIButton+AFNetworking.h可以给按钮加载异步图片;
  /**
     Asynchronously downloads an image from the specified URL, and sets it as the image for the specified state once the request is finished. Any previous image request for the receiver will be cancelled.

      If the image is cached locally, the image is set immediately, otherwise the   specified placeholder image will be set immediately, and then the remote image will   be set once the request is finished.
  
     @param state The control state.
     @param url The URL used for the image request.
     */
      - (void)setImageForState:(UIControlState)state
                 withURL:(NSURL *)url;

  /**
   Asynchronously downloads an image from the specified URL, and sets it as the image for the specified state once the request is finished. Any previous image request for the receiver will be cancelled.

   If the image is cached locally, the image is set immediately, otherwise the specified placeholder image will be set immediately, and then the remote image will be set once the request is finished.

   @param state The control state.
   @param url The URL used for the image request.
   @param placeholderImage The image to be set initially, until the image request finishes. If `nil`, the button will not change its image until the image request finishes.
   */
- (void)setImageForState:(UIControlState)state
                 withURL:(NSURL *)url
        placeholderImage:(nullable UIImage *)placeholderImage;
  • UIImageView+AFNetworking.h也可以加载异步图片;
    /**
     Asynchronously downloads an image from the specified URL, and sets it once the request is finished. Any previous image request for the receiver will be cancelled.

       If the image is cached locally, the image is set immediately, otherwise the specified placeholder image will be set immediately, and then the remote image will be set once the request is finished.

       By default, URL requests have a `Accept` header field value of "image / *", a cache policy of `NSURLCacheStorageAllowed` and a timeout interval of 30 seconds, and are set not handle cookies. To configure URL requests differently, use `setImageWithURLRequest:placeholderImage:success:failure:`

       @param url The URL used for the image request.
       */
      - (void)setImageWithURL:(NSURL *)url;

      /**
       Asynchronously downloads an image from the specified URL, and sets it once the request is finished. Any previous image request for the receiver will be cancelled.

       If the image is cached locally, the image is set immediately, otherwise the specified placeholder image will be set immediately, and then the remote image will be set once the request is finished.

       By default, URL requests have a `Accept` header field value of "image / *", a cache policy of `NSURLCacheStorageAllowed` and a timeout interval of 30 seconds, and are set not handle cookies. To configure URL requests differently, use `setImageWithURLRequest:placeholderImage:success:failure:`

       @param url The URL used for the image request.
       @param placeholderImage The image to be set initially, until the image request finishes. If `nil`, the image view will not change its image until the image request finishes.
 */
      - (void)setImageWithURL:(NSURL *)url
       placeholderImage:(nullable UIImage *)placeholderImage;
  • UIActivityIndicatorView+AFNetworkingUIRefreshControl+AFNetworking.hUIWebView+AFNetworking.hUIProgressView+AFNetworking.h也是一些UI的自定义效果,可以自己试试看。

待续


  • AFSecurityPolicy,安全相关的AFSecurityPolicy模块,AFSecurityPolicy用于验证HTTPS请求的证书优待金一步了解...

讲完了


  • 暂时所知,倾囊相授,3ks~
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,524评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,869评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,813评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,210评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,085评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,117评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,533评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,219评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,487评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,582评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,362评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,218评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,589评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,899评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,176评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,503评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,707评论 2 335

推荐阅读更多精彩内容