AFNetworking

iOS开发中往往会涉及到网络数据处理,在iOS 7之前,iOS提供的网络架构叫 NSURLConnection;在iOS7中,Apple更新了iOS中的网络架构 NSURLSession。AFNetworking则是基于这两个框架而设计的第三方开源库。

体系结构

NSURLConnection

AFNetworking 包含的组件:

  • AFURLConnectionOperation - NSOperation 的子类,负责管理 NSURLConnection 并且实现其 delegate 方法。
  • AFHTTPRequestOperation - AFURLConnectionOperation 的子类,用于生成 HTTP 请求,可以区别可接受的和不可接受的状态码及内容类型。 2.0 版本中的最大区别是,你可以直接使用这个类,而不用继承它,原因可以在“序列化”一节中找到。
  • AFHTTPRequestOperationManager - 封装常见 HTTP web 服务操作的类,包括创建请求、响应序列化、网络可达性监测、安全性和请求操作管理。通过 AFHTTPRequestOperation 由 NSURLConnection 支持。

NSURLSession (iOS 7 / Mac OS X 10.9)

AFNetworking 包含的组件:

  • AFURLSessionManager - 创建、管理基于 NSURLSessionConfiguration 对象的 NSURLSession 对象的类, 也可以管理 session 的数据、下载/上传任务,实现 session 和其相关联的任务的 delegate 方法。因为 NSURLSession API 设计中奇怪的空缺,任何和 NSURLSession 相关的代码都可以用 AFURLSessionManager 改善。
  • AFHTTPSessionManager - AFURLSessionManager 的子类,包装常见的 HTTP web 服务操作,通过 AFURLSessionManager 由 NSURLSession 支持。

序列化

AFNetworking 2.0 新构架的突破之一是使用序列化来创建请求、解析响应。可以通过序列化的灵活设计将更多业务逻辑转移到网络层,并更容易定制之前内置的默认行为。

请求序列化

<AFURLRequestSerialization>

符合这个协议的对象用于处理请求,它将请求参数转换为 query string 或是 entity body 的形式,并设置必要的 header。

  • AFHTTPRequestSerializer
  • AFJSONRequestSerializer
  • AFPropertyListRequestSerializer

响应序列化

<AFURLResponseSerialization>

符合这个协议的对象用于验证、序列化响应及相关数据,转换为有用的形式,比如 JSON 对象、图像、甚至基于 Mantle 的模型对象。

  • AFHTTPResponseSerializer
  • AFJSONResponseSerializer
  • AFXMLParserResponseSerializer
  • AFXMLDocumentResponseSerializer (Mac OS X)
  • AFPropertyListResponseSerializer
  • AFImageResponseSerializer
  • AFCompoundResponseSerializer

Additional Functionality

  • AFSecurityPolicy
  • AFNetworkReachabilityManager

使用

AFHTTPRequestOperationManager

GET Request

// GET
AFHTTPRequestOperationManager* manager = [AFHTTPRequestOperationManager manager];
[manager GET:@"http://example.com/resources.json"
    parameters:nil
    success:^(AFHTTPRequestOperation* operation, id responseObject) {
         NSLog(@"JSON: %@", responseObject);
    }
    failure:^(AFHTTPRequestOperation* operation, NSError* error) {
         NSLog(@"Error: %@", error);
    }];

POST URL-Form-Encoded Request

// POST
AFHTTPRequestOperationManager* manager = [AFHTTPRequestOperationManager manager];
NSDictionary* parameters = @{ @"foo" : @"bar" };
[manager POST:@"http://example.com/resources.json"
    parameters:parameters
    success:^(AFHTTPRequestOperation* operation, id responseObject) {
          NSLog(@"JSON: %@", responseObject);
    }
    failure:^(AFHTTPRequestOperation* operation, NSError* error) {
          NSLog(@"Error: %@", error);
    }];

POST Multi-Part Request

// Multi-Part Request
AFHTTPRequestOperationManager* manager =
    [AFHTTPRequestOperationManager manager];
NSDictionary* parameters = @{ @"foo" : @"bar" };
NSURL* filePath = [NSURL fileURLWithPath:@"file://path/to/image.png"];
[manager POST:@"http://example.com/resources.json"
   parameters:parameters
   constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
        [formData appendPartWithFileURL:filePath name:@"image" error:nil];
    }
      success:^(AFHTTPRequestOperation* operation, id responseObject) {
          NSLog(@"Success: %@", responseObject);
    }
      failure:^(AFHTTPRequestOperation* operation, NSError* error) {
          NSLog(@"Error: %@", error);
    }];

AFURLSessionManager

Creating a Download Task

// Creating a Download Task
NSURLSessionConfiguration* configuration =
    [NSURLSessionConfiguration defaultSessionConfiguration];
AFURLSessionManager* manager =
    [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];

NSURL* URL = [NSURL URLWithString:@"http://example.com/download.zip"];
NSURLRequest* request = [NSURLRequest requestWithURL:URL];

NSURLSessionDownloadTask* downloadTask
    = [manager downloadTaskWithRequest:request
                              progress:nil
                           destination:^NSURL*(NSURL* targetPath, NSURLResponse* response) {
                               NSURL* documentsDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory
                                                                           inDomain:NSUserDomainMask
                                                                  appropriateForURL:nil
                                                                             create:NO
                                                                              error:nil];
                               return [documentsDirectoryURL URLByAppendingPathComponent:[response suggestedFilename]];
                           }
                     completionHandler:^(NSURLResponse* response, NSURL* filePath, NSError* error) {
                         NSLog(@"File downloaded to: %@", filePath);
                     }];
[downloadTask resume];

Creating an Upload Task

// Creating an Upload Task
NSURLSessionConfiguration* configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
AFURLSessionManager* manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];

NSURL* URL = [NSURL URLWithString:@"http://example.com/upload"];
NSURLRequest* request = [NSURLRequest requestWithURL:URL];
NSURL* filePath = [NSURL fileURLWithPath:@"file://path/to/image.png"];

NSURLSessionUploadTask* uploadTask
    = [manager uploadTaskWithRequest:request
                            fromFile:filePath
                            progress:nil
                   completionHandler:^(NSURLResponse* response, id responseObject, NSError* error) {
                       if (error) {
                           NSLog(@"Error: %@", error);
                       } else {
                           NSLog(@"Success: %@ %@", response, responseObject);
                       }
                   }];
[uploadTask resume];

Creating an Upload Task for a Multi-Part Request, with Progress

// Creating an Upload Task for a Multi-Part Request, with Progress
NSMutableURLRequest* request
    = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:@"POST"
                                                                 URLString:@"http://example.com/upload"
                                                                parameters:nil
                                                 constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
                                                     [formData appendPartWithFileURL:[NSURL fileURLWithPath:@"file://path/to/image.jpg"]
                                                                                name:@"file"
                                                                            fileName:@"filename.jpg"
                                                                            mimeType:@"image/jpeg"
                                                                               error:nil];
                                                 }
                                                                     error:nil];

AFURLSessionManager* manager
    = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
NSProgress* progress = nil;

NSURLSessionUploadTask* uploadTask
    = [manager uploadTaskWithStreamedRequest:request
                                    progress:&progress
                           completionHandler:^(NSURLResponse* response, id responseObject, NSError* error) {
                               if (error) {
                                   NSLog(@"Error: %@", error);
                               } else {
                                   NSLog(@"%@ %@", response, responseObject);
                               }
                           }];

[uploadTask resume];

Creating a Data Task

// Creating a Data Task
NSURLSessionConfiguration* configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
AFURLSessionManager* manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];

NSURL* URL = [NSURL URLWithString:@"http://example.com/upload"];
NSURLRequest* request = [NSURLRequest requestWithURL:URL];

NSURLSessionDataTask* dataTask
    = [manager dataTaskWithRequest:request
                 completionHandler:^(NSURLResponse* response, id responseObject, NSError* error){
                     if (error) {
                         NSLog(@"Error: %@", error);
                     } else {
                         NSLog(@"%@ %@", response, responseObject);
                     }
                 }];
[dataTask resume];

AFHTTPRequestOperation

尽管生成请求最好使用AFHTTPRequestOperationManager,但AFHTTPRequestOperation也可以独立使用。

使用AFHTTPRequestOperation进行 GET 请求

// 1. urlsting->url->urlRequest
NSURL* URL = [NSURL URLWithString:@"http://example.com/resources/123.json"];
NSURLRequest* request = [NSURLRequest requestWithURL:URL];
// 2 新建 AFHTTPRequestOperation 并设置 responseSerializer:AFJSONResponseSerializer、AFPropertyListResponseSerializer等
AFHTTPRequestOperation* op = [[AFHTTPRequestOperation alloc] initWithRequest:request];
op.responseSerializer = [AFJSONResponseSerializer serializer];
// 3 设置 completion block
[op setCompletionBlockWithSuccess:^(AFHTTPRequestOperation* operation, id responseObject) {
    // serializer 会解析接收到的数据,返回一个responseObject
    NSLog(@"JSON: %@", responseObject);
} failure:^(AFHTTPRequestOperation* operation, NSError* error) {
    NSLog(@"Error: %@", error);
}];
// 4 开始
[operation start];//或    [[NSOperationQueue mainQueue] addOperation:op];

批处理

// 批处理
NSMutableArray* mutableOperations = [NSMutableArray array];
for (NSURL* fileURL in filesToUpload) {
    NSURLRequest* request = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:@"POST" URLString:@"http://example.com/upload" parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
        [formData appendPartWithFileURL:fileURL name:@"images[]" error:nil];
    }];

    AFHTTPRequestOperation* operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];

    [mutableOperations addObject:operation];
}

NSArray* operations = [AFURLConnectionOperation batchOfRequestOperations:@[... ] progressBlock:^(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations) {
    NSLog(@"%lu of %lu complete", numberOfFinishedOperations, totalNumberOfOperations);
} completionBlock:^(NSArray* operations) {
    NSLog(@"All operations in batch complete");
}];
[[NSOperationQueue mainQueue] addOperations:operations waitUntilFinished:NO];

最佳实践

AFHTTPRequestOperation用于创建一次性的网络操作,而AFHTTPRequestOperationManagerAFHTTPSessionManager可方便的用于和单个 Web 服务终端交互。在项目中使用使用AFHTTPSessionManager可以使得网络通信代码复用:

  1. 为每一个 Web 服务创建一个子类。如在写一个社交网络整合的应用,可以为 Twitter、Facebook 等各建一个子类。
  2. 在每一个子类中创建一个类方法返回共享单例,可以节省资源。
//单例
- (WeatherHTTPClient*)sharedWeatherHTTPClient
{
    static WeatherHTTPClient* _sharedWeatherHTTPClient = nil;

    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _sharedWeatherHTTPClient = [[self alloc] initWithBaseURL:[NSURL URLWithString:WorldWeatherOnlineURLString]];
        });

        return _sharedWeatherHTTPClient;
    }

UIKit 扩展

  • AFNetworkActivityIndicatorManager:在请求操作开始、停止加载时,自动开始、停止状态栏上的网络活动指示图标。
// AFNetworkActivityIndicatorManager
[AFNetworkActivityIndicatorManager sharedManager].enabled = YES;
  • UIImageView+AFNetworking(setImageWithURLRequest:):增加了 imageResponseSerializer 属性,可以轻松地让远程加载到 image view 上的图像自动调整大小或应用滤镜。比如,AFCoreImageSerializer 可以在 response 的图像显示之前应用 Core Image filter。
// UIImageView+AFNetworking
NSURL* url = [NSURL URLWithString:daysWeather.weatherIconURL];
NSURLRequest* request = [NSURLRequest requestWithURL:url];
UIImage* placeholderImage = [UIImage imageNamed:@"placeholder"];

__weak UITableViewCell* weakCell = cell;

[cell.imageView setImageWithURLRequest:request
                      placeholderImage:placeholderImage
                               success:^(NSURLRequest* request, NSHTTPURLResponse* response, UIImage* image) {
                                   weakCell.imageView.image = image;
                                   [weakCell setNeedsLayout];
                               }
                               failure:nil];// 两个 block 都是可选的。若没有 success,imageView 自动设置远程图片,若有,则必须明确设置图片
  • UIButton+AFNetworking:与 UIImageView+AFNetworking 类似,从远程资源加载 image 和 backgroundImage。

  • UIActivityIndicatorView+AFNetworking:根据指定的请求操作和会话任务的状态自动开始、停止 UIActivityIndicatorView。

  • UIProgressView+AFNetworking:自动跟踪某个请求或会话任务的上传/下载进度。

  • UIWebView+AFNetworking (新): 为加载 URL 请求提供了更强大的API,支持进度回调和内容转换。

参考

https://github.com/AFNetworking/AFNetworking

http://www.raywenderlich.com/59255/afnetworking-2-0-tutorial

http://nshipster.cn/afnetworking-2/

Loading Disqus comments...
Table of Contents