美文网首页iOS Framework
AFNetwork 3.x 在开发中常用基础的介绍

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

作者: 刘是丑 | 来源:发表于2016-05-16 13:01 被阅读461次

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

    从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~

    相关文章

      网友评论

      • jimmylin:非常受用!谢谢了!辛苦了!

      本文标题:AFNetwork 3.x 在开发中常用基础的介绍

      本文链接:https://www.haomeiwen.com/subject/gsrbrttx.html