iOS Framework

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

2016-05-16  本文已影响461人  刘是丑

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

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

要讲什么


开始讲了


1、AFNetworking的基本使用

  - (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);
    }];
}
  - (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上传文件

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的序列化

请求格式:
 AFHTTPRequestSerializer              二进制格式
 AFJSONRequestSerializer              JSON
 AFPropertyListRequestSerializer      PList(是一种特殊的XML)

返回格式:
 AFHTTPResponseSerializer             二进制格式
 AFJSONResponseSerializer             JSON
 AFXMLParserResponseSerializer        XML,只能返回XMLParser,还需要自己通过代理方法解析
 AFXMLDocumentResponseSerializer     (Mac OS X)
 AFPropertyListResponseSerializer     PList
 AFImageResponseSerializer            Image
 AFCompoundResponseSerializer         组合
问题:  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使用小技巧

6、AFNetworking的附加Category使用

/**
 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;
  /**
     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;
    /**
     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;

待续


讲完了


上一篇 下一篇

猜你喜欢

热点阅读