AFNetworking源码笔记

在这里插入图片描述


最近又重新看了一遍AFNetworking,温故知新,因为以前看是看过,也基于AFNetworking封装过网络请求,只是很多点不明白作者为什么那么写,也没深究和记录。这次主要是想在AFNetworking的整体架构和设计方式上分析总结。源码解析推荐这篇文章(AFNetworking到底做了什么?
准备工作:git上下载zip文件,不用pod主要是想添加自己的注解,可以看到文件只有AFNetworking和UIKit+AFNetworking在这里插入图片描述
而不是平时我们看到pod中
在这里插入图片描述
也就是人为分了5个模块:

NSURLSession
Reachability
Serialization
Security
UIKit
在这里插入图片描述
说好的不看具体细节,因为前面有大神写好的非常详细文章,还是忍不住画了一下里面结构分类,这里主要是想在心中有个清晰的框架结构。
Demo地址:https://github.com/asd521411/AFNetworkingNote.git

1、网络请求的步骤

  • 创建一个请求
    NSURLRequest:(包含默认的请求头信息)
    NSMutableURLRequest:HTTPMethod、setValue:forHTTPHeaderField:、HTTPBody
  • 建立连接:
    NSURLConnection(NSURLConnection只会开启一条线程,iOS 9已经弃用)
    NSURLSession(创建会话)
    NSURLSessionDataTask(会话任务)
  • 创建一个统一网络请求地址:NSURL
  • 创建一个请求
    NSURLRequest:(包含默认的请求头信息)
    NSMutableURLRequest:HTTPMethod、setValue:forHTTPHeaderField:、HTTPBody
  • 建立连接:
    NSURLConnection(NSURLConnection只会开启一条线程,iOS 9已经弃用)
    NSURLSession(创建会话)
    NSURLSessionDataTask(会话任务)

这是最基本的过程,AFNetworking就是对这些请求的方法做了一些封装(这不废话吗)。

  • NSURLSession下面有两个主要文件

AFHTTPSessionManager
AFURLSessionManager

AFHTTPSessionManager

AFHTTPSessionManager继承于AFURLSessionManager,AFURLSessionManager里面做的事情有:

  • 初始化,最终调用的是
- (instancetype)initWithBaseURL:(NSURL *)url sessionConfiguration:(NSURLSessionConfiguration *)configuration
  • 无论GET、POST、HEAD、PUT、PATCH、DELETE最后走的是这个方法
- (NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)method
                                       URLString:(NSString *)URLString
                                      parameters:(id)parameters
                                  uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgress
                                downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgress
                                         success:(void (^)(NSURLSessionDataTask *, id))success
                                         failure:(void (^)(NSURLSessionDataTask *, NSError *))failure

这个方法里面做了两件事情,就是网络请求基本过程中的创建NSMutableURLRequest请求

NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:&serializationError];
    if (serializationError) {
        if (failure) {
        	//判断是否有回调队列,如果有在异步队列中返回否则在主队了中返回错误
            dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
                failure(nil, serializationError);
            });
        }
        return nil;
    }

和NSURLSessionDataTask请求的的回调

[self dataTaskWithRequest:request
                          uploadProgress:uploadProgress
                        downloadProgress:downloadProgress
                       completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {}];
  • 序列化和反序列化拿到(具体看initWithCoder:和encodeWithCoder:里面代码)
    self.session.configuration
    self.requestSerializer
    self.responseSerializer
    self.securityPolicy
  • 遵守NSCopying协议
- (instancetype)copyWithZone:(NSZone *)zone {
    AFHTTPSessionManager *HTTPClient = [[[self class] allocWithZone:zone] initWithBaseURL:self.baseURL sessionConfiguration:self.session.configuration];

    HTTPClient.requestSerializer = [self.requestSerializer copyWithZone:zone];
    HTTPClient.responseSerializer = [self.responseSerializer copyWithZone:zone];
    HTTPClient.securityPolicy = [self.securityPolicy copyWithZone:zone];
    return HTTPClient;
}

AFURLSessionManager里面做的事情

AFURLSessionManager主要是对核心类及其代理的封装
核心类

NSURLSession
NSURLSessionConfiguration
NSURLSessionTask(抽象类)

1.NSURLSessionDataTask
2.NSURLSessionDownload

代理

NSURLSessionDelegate
NSURLSessionTaskDelegate
NSURLSessionDataDelegate
NSURLSessionDownloadDelegate

NSURLSession官方文档:https://developer.apple.com/documentation/foundation/nsurlsession
具体细节看官方文档

NSURLSession
NSURLSessionDelegate
定义URL会话实例调用其委托来处理会话级事件(如会话生命周期更改)的方法的协议

NSURLSessionTask(抽象类)
NSURLSessionTaskDelegate
定义URL会话实例调用其委托来处理任务级事件的方法的协议,也就是处理任务时的代理。

NSURLSessionDataTask
一个URL会话任务,它将下载的数据直接返回到内存中的应用程序
NSURLSessionDataDelegate

NSURLSessionDownload
NSURLSessionDownloadDelegate

AFURLSessionManager具体做的事情

  • 初始化initWithSessionConfiguration:里面
    初始化会话配置、JSON响应、默认安全策略不罗列,看源码
    //初始化一个队列,并发数为1,用来处理会话的代理
    self.operationQueue = [[NSOperationQueue alloc] init];
    self.operationQueue.maxConcurrentOperationCount = 1;
    self.session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue];
    //self.mutableTaskDelegatesKeyedByTaskIdentifier
    让每一个请求task和自定义的AF代理来建立映射。其实AF对task的代理进行了一个封装,并且转发代理到AF自定义的代理。
  • 异步的获取当前session的所有未完成的task, 防止后台回来,重新初始化这个session,一些之前的后台请求任务,导致程序的crash
[self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) { 
}];
  • 设置NSMutableURLRequest的属性,并且监听属性的变化,如果改变则把改变的属性放到self.mutableObservedChangedKeyPaths (NSMutableSet类型)里面,在请求的时候从self.mutableObservedChangedKeyPaths里面取出赋值给NSMutableURLRequest属性
    定义了一个C语言函数,管理NSMutableURLRequest的属性变化
static NSArray * AFHTTPRequestSerializerObservedKeyPaths() {
    static NSArray *_AFHTTPRequestSerializerObservedKeyPaths = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _AFHTTPRequestSerializerObservedKeyPaths = @[NSStringFromSelector(@selector(allowsCellularAccess)), NSStringFromSelector(@selector(cachePolicy)), NSStringFromSelector(@selector(HTTPShouldHandleCookies)), NSStringFromSelector(@selector(HTTPShouldUsePipelining)), NSStringFromSelector(@selector(networkServiceType)), NSStringFromSelector(@selector(timeoutInterval))];
    });
    return _AFHTTPRequestSerializerObservedKeyPaths;
}

初始化的时候添加观察者

self.mutableObservedChangedKeyPaths = [NSMutableSet set];
    for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) {
        if ([self respondsToSelector:NSSelectorFromString(keyPath)]) {
            [self addObserver:self forKeyPath:keyPath options:NSKeyValueObservingOptionNew context:AFHTTPRequestSerializerObserverContext];
        }
    }

是否手动触发KVO通知

+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key {
    if ([AFHTTPRequestSerializerObservedKeyPaths() containsObject:key]) {
        return NO;
    }
    return [super automaticallyNotifiesObserversForKey:key];
}
  • 串行执行任务NSURLSessionDataTask
    NSURLSession内部去生成task的时候是用多线程并发去执行的。为了适配iOS8的以下,创建session的时候,偶发的情况会出现session的属性taskIdentifier这个值不唯一,而这个taskIdentifier是我们后面来映射delegate的key,所以它必须是唯一的。
dispatch_sync(url_session_manager_creation_queue(), block);
  • AF代理和task建立映射,存在事先声明好的字典里。
- (void)setDelegate:(AFURLSessionManagerTaskDelegate *)delegate
            forTask:(NSURLSessionTask *)task
基本流程
  • 通常在主线程初始化sessionManager
  • 调用get、post等去请求数据,接着会进行request拼接,AF代理的字典映射,progress的KVO添加等等,到NSUrlSession的resume之前这些准备工作,仍旧是在主线程中的。
  • 调用NSUrlSession的resume,接着就跑到NSUrlSession内部去对网络进行数据请求了,在它内部是多线程并发的去请求数据的。
  • 紧接着数据请求完成后,回调回来在我们一开始生成的并发数为1的NSOperationQueue中,这个时候会是多线程串行的回调回来的。
  • 然后我们到返回数据解析那一块,我们自己又创建了并发的多线程,去对这些数据进行了各种类型的解析。
  • 如果有自定义的completionQueue,则在自定义的queue中回调回来,也就是分线程回调回来,否则就是主队列,主线程中回调结束。
2、非AFNetworking网络请求的代码实现
  • 创建一个统一网络请求地址:NSURL
  • 创建一个请求
    NSURLRequest:(包含默认的请求头信息)
    NSMutableURLRequest:HTTPMethod、setValue:forHTTPHeaderField:、HTTPBody
  • 建立连接:
    NSURLConnection(NSURLConnection只会开启一条线程,iOS 9已经弃用)
    NSURLSession(创建会话)
    NSURLSessionDataTask(会话任务)

NSURLRequest:
NSMutableURLRequest:可变的请求对象,比如用POST请的时候要修改请求方法,这是请求就不能用NSURLRequest,要用NSMutableURLRequest。
还是看一下用法:

  • NSURLConnection
- (void)connection {
	//1、设置请求信息
    NSString *urlStr = [NSString stringWithFormat:@""];
    //urlStr = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];//GET需要转码,POST不需要,因为post参数不是直接拼接在后面
    NSURL *url = [NSURL URLWithString:@""];//url有中文需要转码
    NSURLRequest *request = [NSURLRequest requestWithURL:url];//默认生成请求头信息

	//POST方式
    NSMutableURLRequest *mutRequest = [NSMutableURLRequest requestWithURL:url];
    mutRequest.HTTPMethod = @"POST";
    //设置请求头信息
    [mutRequest setValue:@"iOS-Client" forHTTPHeaderField:@"User-Agent"];
    //超时请求失败
    mutRequest.timeoutInterval = 3;
    mutRequest.HTTPBody = [@"username=zhw&pwd=123456&type=JSON" dataUsingEncoding:NSUTF8StringEncoding];

    NSURLResponse *response = nil;//响应头信息
    NSError *error = nil;
    //2、请求方式
    //2.1同步block方式,此时NSData就是响应体信息
    NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
    //解析服务器返回的数据
    NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    
    //2.2异步请求,block方式
    [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
    }];
    
    //2.3 NSURLConnectionDataDelegate的代理方式
    NSURLConnection *connect = [[NSURLConnection alloc] initWithRequest:request delegate:self];
    //请求状态
    [connect cancel];
}

//NSURLConnectionDataDelegate的代理方法
- (nullable NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(nullable NSURLResponse *)response;
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response;
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data;
- (nullable NSInputStream *)connection:(NSURLConnection *)connection needNewBodyStream:(NSURLRequest *)request;
- (void)connection:(NSURLConnection *)connection   didSendBodyData:(NSInteger)bytesWritten
                                                 totalBytesWritten:(NSInteger)totalBytesWritten
                                         totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite;
- (nullable NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse;
- (void)connectionDidFinishLoading:(NSURLConnection *)connection;

  • NSURLSession

使用NSURLSession对象创建Task,然后执行Task,可以开启多条线程。
Task

  • NSURLSessionTask抽象类,用他的两个子类
    1、NSURLSessionDataTask

    NSURLSessionUploadTask

    2、NSURLSessionDownloadTask

- (void)session {
    
    NSURL *url = [NSURL URLWithString:@""];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    
    //POST方式
    NSMutableURLRequest *mutRequest = [NSMutableURLRequest requestWithURL:url];
    mutRequest.HTTPMethod = @"POST";
    //设置请求头信息
    [mutRequest setValue:@"iOS-Client" forHTTPHeaderField:@"User-Agent"];
    //超时请求失败
    mutRequest.timeoutInterval = 3;
    mutRequest.HTTPBody = [@"username=zhw&pwd=123456&type=JSON" dataUsingEncoding:NSUTF8StringEncoding];
   
    //创建会话,如果用代理模式返回,就不能用单例模式创建,要自定义创建
    NSURLSession *session = [NSURLSession sharedSession];
    
    //block模式
    NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        //注意是子线程
    }];
    
    //NSURLSessionDataDelegate模式,要自定义创建NSURLSession,不能用单例模式创建,代理线程队列决定代理方法在哪个线程中执行,传nil在子线程中执行。
    NSURLSession *sess = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[[NSOperationQueue alloc] init]];
    NSURLSessionDataTask *ta = [sess dataTaskWithRequest:request];
    
    //默认是挂起状态,恢复执行NSURLSession的代理
    [task resume];
    [ta resume];
}
//
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
                                 didReceiveResponse:(NSURLResponse *)response
                                  completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler {
    //需要通过completionHandler告诉s服务器如何处理返回的数据
    completionHandler(NSURLSessionResponseAllow);//告诉服务器结束数据
    //打印代理发现也是在子线程中执行的
    NSLog(@"%@", [NSThread currentThread]);
 }
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
                              didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask;

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
                                didBecomeStreamTask:(NSURLSessionStreamTask *)streamTask;

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
                                     didReceiveData:(NSData *)data;

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
                                  willCacheResponse:(NSCachedURLResponse *)proposedResponse
                                  completionHandler:(void (^)(NSCachedURLResponse * _Nullable cachedResponse))completionHandler;

3、数据解析的方式
  • JSON解析

JSON解析三方框架:
JSONKit、SBJson、TouchJSON,性能依次递减
苹果原生自带:NSJSONSerialization(性能最好)

- (void)json {
    //JSON-->OC(反序列化)
    //+ (nullable id)JSONObjectWithData:(NSData *)data options:(NSJSONReadingOptions)opt error:(NSError **)error;
    //OC-->JSON(序列化)
    //+ (nullable NSData *)dataWithJSONObject:(id)obj options:(NSJSONWritingOptions)opt error:(NSError **)error;
    
    NSDictionary *dic = @{@"name":@"zhw", @"age":@"18"};
    NSData *data = [NSJSONSerialization dataWithJSONObject:dic options:NSJSONWritingPrettyPrinted error:nil];
    
    //并不是所有OC对象都能转成JSON,字符串不行
    NSString *str = @"这是一个无聊的字符串";
    if ([NSJSONSerialization isValidJSONObject:str]) {//判断对象能否序列化
    }
    
    //要把OC对象转成JSON的二进制形式(NSData)再写入文件
    [data writeToFile:@"filename" atomically:YES];
    
    //复杂JSON解析三方推荐:MJExtension
}
  • XML解析

XML的解析方式有两种:
DOM:一次性将整个XML文件加载进内存,比较适合解析小文件
SAX:从根元素开始,按顺序一个元素一个元素往下解析,比较适合解析大文件
苹果原生:NSXMLParser,SAX解析方式,使用简单
三方框架:libxml2:纯C,默认包含在iOS SDK中,同时支持DOM、SAX解析方式
GDataXML:DOM方式,由Google开发,基于libxml2
大文件建议:NSXMLParser、libxml2


- (void)xml {
    NSData *data = [NSData dataWithContentsOfFile:@""];
    NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
    parser.delegate = self;
    //开始解,阻塞式的
    [parser parse];
}
//NSXMLParserDelegate
- (void)parserDidStartDocument:(NSXMLParser *)parser;
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary<NSString *,NSString *> *)attributeDict {
    //过滤掉根元素
    if ([elementName isEqualToString:@""]) {
    }
}
- (void)parserDidEndDocument:(NSXMLParser *)parser;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值