请选择 进入手机版 | 继续访问电脑版
afnetworking.png
写在开头:

作为一个iOS开发,也许你不知道NSUrlRequest、不知道NSUrlConnection、也不知道NSURLSession...(说不下去了...怎么会什么都不知道...)但是你一定知道AFNetworking。
大多数人习惯了只要是请求网络都用AF,但是你真的知道AF做了什么吗?为什么我们不用原生的NSURLSession而选择AFNetworking?
本文将从源码的角度去分析AF的实际作用。
或许看完这篇文章,你心里会有一个答案。

先从最新的AF3.x讲起吧:
  • 首先,我们就一起分析一下该框架的组成。
    将AF下载导入工程后,下面是其包结构,相对于2.x变得非常简单了:
afnetworking框架.jpeg

除去Support Files,可以看到AF分为如下5个功能模块:
  • 网络通信模块(AFURLSessionManager、AFHTTPSessionManger)
  • 网络状态监听模块(Reachability)
  • 网络通信安全策略模块(Security)
  • 网络通信信息序列化/反序列化模块(Serialization)
  • 对于iOS UIKit库的扩展(UIKit)
其核心当然是网络通信模块AFURLSessionManager。大家都知道,AF3.x是基于NSURLSession来封装的。所以这个类围绕着NSURLSession做了一系列的封装。而其余的四个模块,均是为了配合网络通信或对已有UIKit的一个扩展工具包。
这五个模块所对应的类的结构关系图如下所示:
afnetworking架构图.jpeg
其中AFHTTPSessionManager是继承于AFURLSessionManager的,我们一般做网络请求都是用这个类,但是它本身是没有做实事的,只是做了一些简单的封装,把请求逻辑分发给父类AFURLSessionManager或者其它类去做。
首先我们简单的写个get请求:
[Objective-C] 纯文本查看 复制代码
AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc]init];

[manager GET:@"http://localhost" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {

} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {

}];
首先我们我们调用了初始化方法生成了一个manager,我们点进去看看初始化做了什么:
[Objective-C] 纯文本查看 复制代码
- (instancetype)init {
    return [self initWithBaseURL:nil];
}

- (instancetype)initWithBaseURL:(NSURL *)url {
    return [self initWithBaseURL:url sessionConfiguration:nil];
}

- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
    return [self initWithBaseURL:nil sessionConfiguration:configuration];
}

- (instancetype)initWithBaseURL:(NSURL *)url
           sessionConfiguration:(NSURLSessionConfiguration *)configuration
{
    self = [super initWithSessionConfiguration:configuration];
    if (!self) {
        return nil;
    }
    //对传过来的BaseUrl进行处理,如果有值且最后不包含/,url加上"/"
  //--经一位热心读者更正...以后注释也一定要走心啊...不能误导大家...
    if ([[url path] length] > 0 && ![[url absoluteString] hasSuffix:@"/"]) {
        url = [url URLByAppendingPathComponent:@""];
    }

    self.baseURL = url;

    self.requestSerializer = [AFHTTPRequestSerializer serializer];
    self.responseSerializer = [AFJSONResponseSerializer serializer];

    return self;
}
  • 初始化都调用到- (instancetype)initWithBaseURL:(NSURL *)url sessionConfiguration:(NSURLSessionConfiguration *)configuration方法中来了。
  • 其实初始化方法都调用父类的初始化方法。父类也就是AF3.x最最核心的类AFURLSessionManager。几乎所有的类都是围绕着这个类在处理业务逻辑。
  • 除此之外,方法中把baseURL存了起来,还生成了一个请求序列对象和一个响应序列对象。后面再细说这两个类是干什么用的。
直接来到父类AFURLSessionManager的初始化方法:
[Objective-C] 纯文本查看 复制代码
- (instancetype)init {
    return [self initWithSessionConfiguration:nil];
}

- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
    self = [super init];
    if (!self) {
        return nil;
    }
    if (!configuration) {
        configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    }
    self.sessionConfiguration = configuration;
    self.operationQueue = [[NSOperationQueue alloc] init];
    //queue并发线程数设置为1
    self.operationQueue.maxConcurrentOperationCount = 1;

    //注意代理,代理的继承,实际上NSURLSession去判断了,你实现了哪个方法会去调用,包括子代理的方法!
    self.session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue];

    //各种响应转码
    self.responseSerializer = [AFJSONResponseSerializer serializer];

    //设置默认安全策略
    self.securityPolicy = [AFSecurityPolicy defaultPolicy];

#if !TARGET_OS_WATCH
    self.reachabilityManager = [AFNetworkReachabilityManager sharedManager];
#endif
    // 设置存储NSURL task与AFURLSessionManagerTaskDelegate的词典(重点,在AFNet中,每一个task都会被匹配一个AFURLSessionManagerTaskDelegate 来做task的delegate事件处理) ===============
    self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init];

    //  设置AFURLSessionManagerTaskDelegate 词典的锁,确保词典在多线程访问时的线程安全
    self.lock = [[NSLock alloc] init];
    self.lock.name = AFURLSessionManagerLockName;

    // 置空task关联的代理
    [self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {        
        for (NSURLSessionDataTask *task in dataTasks) {
            [self addDelegateForDataTask:task uploadProgress:nil downloadProgress:nil completionHandler:nil];
        }
        for (NSURLSessionUploadTask *uploadTask in uploadTasks) {
            [self addDelegateForUploadTask:uploadTask progress:nil completionHandler:nil];
        }
        for (NSURLSessionDownloadTask *downloadTask in downloadTasks) {
            [self addDelegateForDownloadTask:downloadTask progress:nil destination:nil completionHandler:nil];
        }
    }];
    return self;
}
这个就是最终的初始化方法了,注释应该写的很清楚,唯一需要说的就是三点:
  • self.operationQueue.maxConcurrentOperationCount = 1;这个operationQueue就是我们代理回调的queue。这里把代理回调的线程并发数设置为1了。至于这里为什么要这么做,我们先留一个坑,等我们讲完AF2.x之后再来分析这一块。
  • 第二就是我们初始化了一些属性,其中包括self.mutableTaskDelegatesKeyedByTaskIdentifier,这个是用来让每一个请求task和我们自定义的AF代理来建立映射用的,其实AF对task的代理进行了一个封装,并且转发代理到AF自定义的代理,这是AF比较重要的一部分,接下来我们会具体讲这一块。
  • 第三就是下面这个方法:
  • [self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) { }];

    • 首先说说这个方法是干什么用的:这个方法用来异步的获取当前session的所有未完成的task。其实讲道理来说在初始化中调用这个方法应该里面一个task都不会有。我们打断点去看,也确实如此,里面的数组都是空的。
      但是想想也知道,AF大神不会把一段没用的代码放在这吧。辗转多处,终于从AF的issue中找到了结论:github  https://github.com/AFNetworking/AFNetworking/issues/3499
      • 原来这是为了从后台回来,重新初始化session,防止一些之前的后台请求任务,导致程序的crash。


初始化方法到这就全部完成了。

文 /涂耀辉(简书作者)
原文链接:http://www.jianshu.com/p/856f0e26279d

举报 使用道具
| 回复

共 0 个关于本帖的回复 最后回复于 2017-1-6 20:47

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

本文内容不够精彩,我要自己发布

发布新帖

推荐阅读

    拥有的,不仅是技术!还有...
    联系 Email: support.36ji@qq.com

    • 关注酷站官方微博
      了解最新动态

    • 关注酷站微信公众号
      这里有好玩的讯息

    • 加入酷站交流群
      不断在这里成长

    © 2014-2017 36ji网络科技有限公司 . All rights reserved.
    京ICP备14001609号

    Archiver|    
    Powered by Discuz! X3.2 © 2001-2013 Comsenz Inc.
    快速回复 返回顶部 返回列表