为什么使用AFNNetWorking

来源:互联网 发布:打开软件速度慢 编辑:程序博客网 时间:2024/05/28 18:43
  1. AFN 与 ASI 有什么区别
    1> AFN基于NSURL,ASI基于底层的CFNetwork框架,因此ASI的性能优于AFN
    2> AFN采取block的方式处理请求,ASI最初采取delegate的方式处理请求,后面也增加了block的方式
    3> AFN只封装了一些常用功能,满足基本需求,直接忽略了很多扩展功能,比如没有封装同步请求;ASI提供的功能较多,预留了各种接口和工具供开发者自行扩展
    4> AFN直接解析服务器返回的JSON、XML等数据,而ASI比较原始,返回的是NSData二进制数据

这里写图片描述
为什么使用AFNNetWorking封装网络请求,AFNNetWorking有哪些方法?
1.1 AFURLConnectionOperation 对网络请求封装的Operation
NSURLConnection的代理方法
SSL 认证
NSCoding 协议
NSCoding 说明
1.1.1 AFN 的属性和方法
1.1.2 实现细节
RunLoop 的作用
NSURLConnection缺陷: 所以在主线程调用异步接口会遇到以下的问题:
AFN 的改进 在子线程调用异步接口
NSURLConnection 不支持后台下载发送请求
AFN 提供了 setShouldExecuteAsBackgroundTaskWithExpirationHandler 决定APP进入到后台后是否继续发送和接收请求
1.2 AFHTTPRequestOperation HTTP 请求真正使用的 Operation 类
1.2.1 请求后的回调的封装
1.2.2 暂停、断点下载续传的实现
1.3 AFHTTPRequestOperationManager request Operation 管理类

1.1 AFURLConnectionOperation 对网络请求封装的Operation

AFURLConnectionOperation 是 NSOperation 的子类,并且实现了 NSURLConnection 的代理方法。这是一个所有网络请求操作的基类。
@interface AFURLConnectionOperation : NSOperation

if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && !defined(AF_APP_EXTENSIONS)

if (_backgroundTaskIdentifier) {    //APP在后台,任务在后台运行,需要告诉系统任务已完成,不然系统会一直让APP运行在后台,直到超时。    [[UIApplication sharedApplication] endBackgroundTask:_backgroundTaskIdentifier];    _backgroundTaskIdentifier = UIBackgroundTaskInvalid;}

endif

}
1.2 AFHTTPRequestOperation HTTP 请求真正使用的 Operation 类

AFHTTPRequestOperation 是 AFURLConnectionOperation 子类,用来请求HTTP 和 HTTPS的协议请求。主要多了 responseSerializer ,暂停下载断点续传,以及提供接口请求成功失败的回调接口 -setCompletionBlockWithSuccess:failure:
我们来看一下请求后的回调
1.2.1 请求后的回调的封装

  • (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
    failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
    {
    // completionBlock is manually nilled out in AFURLConnectionOperation to break the retain cycle.
    self.completionBlock = ^{
    #1
    if (self.completionGroup) {
    dispatch_group_enter(self.completionGroup);
    }
    #2
    dispatch_async(http_request_operation_processing_queue(), ^{
    #3
    if (self.error) {
    if (failure) {
    dispatch_group_async(self.completionGroup ?: http_request_operation_completion_group(), self.completionQueue ?: dispatch_get_main_queue(), ^{
    failure(self, self.error);
    });
    }
    } else {
    #4
    id responseObject = self.responseObject;
    #5
    if (self.error) {
    if (failure) {
    dispatch_group_async(self.completionGroup ?: http_request_operation_completion_group(), self.completionQueue ?: dispatch_get_main_queue(), ^{
    failure(self, self.error);
    });
    }
    } else {
    #6
    if (success) {
    dispatch_group_async(self.completionGroup ?: http_request_operation_completion_group(), self.completionQueue ?: dispatch_get_main_queue(), ^{
    success(self, responseObject);
    });
    }
    }
    }

        if (self.completionGroup) {        dispatch_group_leave(self.completionGroup);    }});

    };
    }

1 : 这里主要是把下列操作添加到全局的group中,可以统一管理

2 : 异步并行执行以下的操作,这里会开子线程

3 : 如果操作失败,那么异步执行 failureBlock 的方法

4 : NSOperation 没有问题,接着进行解析

5 : 在 id responseObject = self.responseObject; 这个语句中,会进行解析,如果解析出错会将error置为nil

6 : 只有当操作正确且解析正确,才会异步调用 successBlock

这里需要注意的是,执行failureBlock 或者 successBlock 所在的线程,取决于有没有设置 self.completionQueue 如果有则提交到设置的队列里,如果没有则默认在主线程执行回调
1.2.2 暂停、断点下载续传的实现

  • (void)pause {
    [super pause];
    // 记录下问卷位置
    u_int64_t offset = 0;
    if ([self.outputStream propertyForKey:NSStreamFileCurrentOffsetKey]) {
    offset = [(NSNumber *)[self.outputStream propertyForKey:NSStreamFileCurrentOffsetKey] unsignedLongLongValue];
    } else {
    offset = [(NSData *)[self.outputStream propertyForKey:NSStreamDataWrittenToMemoryStreamKey] length];
    }

    NSMutableURLRequest *mutableURLRequest = [self.request mutableCopy];
    if ([self.response respondsToSelector:@selector(allHeaderFields)] && [[self.response allHeaderFields] valueForKey:@”ETag”]) {
    //若请求返回的头部有ETag,则续传时要带上这个ETag,ETag用于放置文件的唯一标识,比如文件MD5值
    //续传时带上ETag服务端可以校验相对上次请求,文件有没有变化,若有变化则返回200,回应新文件的全数据,若无变化则返回206续传。
    [mutableURLRequest setValue:[[self.response allHeaderFields] valueForKey:@”ETag”] forHTTPHeaderField:@”If-Range”];
    }
    //给当前request加Range头部,下次请求带上头部,可以从offset位置继续下载
    [mutableURLRequest setValue:[NSString stringWithFormat:@”bytes=%llu-“, offset] forHTTPHeaderField:@”Range”];
    self.request = mutableURLRequest;
    }
    记录下当前下载的位置,还有保存Etag拼接在请求头中,顺便在 请求头中带上 Range 当前已经下载的位置,请求后面的部分
    1.3 AFHTTPRequestOperationManager request Operation 管理类

AFHTTPRequestOperationManager 是用来管理请求的类,这个类里面定义了属性 operationQueue 这个操作队列用来调度和管理所有的 request operation
我们拿GET请求的方法来做例子:
- (AFHTTPRequestOperation )GET:(NSString )URLString
parameters:(id)parameters
success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
{
NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:@”GET” URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:nil];
AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:success failure:failure];

[self.operationQueue addOperation:operation];return operation;

}
首先是用 requestSerializer 创建一个 NSMutableURLRequest 的对象,指定对应的 method 和 url , 并把参数传递。这里 NSMutableURLRequest 可以理解为 HTTP 请求中的网络请求头部分,在这个类里进行配置,而AFN做的操作,就是帮我们完成了配置。 创建完 request 后,用这个请求创建一个对应的 Operation 类,并且把这个 Operation 添加到 刚才所说的全局管理队列 operationQueue 中, 这里 maxConcurrentOperationCount 默认是用系统带的 NSOperationQueueDefaultMaxConcurrentOperationCount 也就是 -1 , 这个默认值会动态的根据当前的系统可用资源来配置最大的并发数量。

0 0
原创粉丝点击