AFNetworking----源码分析浅谈

AFNetworking引言:

iOS网络请求,在iOS7以前,使用NSURLConnection,随着iOS7的发布,出现了NSURLSession处理网络请求.我们开发中使用的三方SDK,如AFNetworking、SDWebImage等等都使用了NSURLSession,都是对它的封装!
本文将从AFNetworking源码入手,简单的探索一下他的实现原理:(iOS小白,请多关照)
AFNetworking版本3.2.1

AFNetworking结构图

AFNetworking结构图

网络请求时,我们使用AFHTTPSessionManager来创建网络请求,它继承自AFURLSessionManager类,看AFHTTPSessionManager类实现我们可以看出,这个类只是做了逻辑的分发工作,网络请求的逻辑给了他的父类AFURLSessionManager以及其他的类去做!

//先来一个网络请求
/**
初始化manager:
AFHTTPSessionManager中,
+ (instancetype)manager;
- (instancetype)initWithBaseURL:(nullable NSURL *)url;
- (instancetype)initWithBaseURL:(nullable NSURL *)url sessionConfiguration:(nullable NSURLSessionConfiguration *)configuration
以及类中的init对象方法,都会调用到本类中的:- (instancetype)initWithBaseURL:(nullable NSURL *)url sessionConfiguration:(nullable NSURLSessionConfiguration *)configuration初始化方法
*/

AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc]init];
[manager GET:@"https://www.baidu.com" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {

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

}];

下面我们来看AFHTTPSessionManager中的initWithBaseURL:sessionConfiguration:方法都做了什么事情

- (instancetype)initWithBaseURL:(NSURL *)url sessionConfiguration:(NSURLSessionConfiguration *)configuration {
	self = [super initWithSessionConfiguration:configuration];
	if (!self) {
    	return nil;
	}
	// Ensure terminal slash for baseURL path, so that NSURL +URLWithString:relativeToURL: works as expected
	//有道翻译:确保baseURL路径的终端斜线,以便NSURL +URLWithString:relativeToURL:按预期工作
	//判断传入的url是否存在且是否是以"/"结尾
	if ([[url path] length] > 0 && ![[url absoluteString] hasSuffix:@"/"]) {
    	url = [url URLByAppendingPathComponent:@""];
	}
	self.baseURL = url;//保存url
	//初始化请求序列化对象和响应序列化对象
	self.requestSerializer = [AFHTTPRequestSerializer serializer];
	self.responseSerializer = [AFJSONResponseSerializer serializer];
	
	return self;
}
/**
从该方法的实现可以看出,该方法只是调用了父类的初始化方法,保存了url以及初始化了两个序列化对象.
*/

现在,我们去看父类的初始化方法做了些什么吧…

- (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];
	//回调队列的并发数
	self.operationQueue.maxConcurrentOperationCount = 1;
	//初始化session,并设置代理
	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
	
	//mutableTaskDelegatesKeyedByTaskIdentifier:字典,存储task唯一对应的mutableTaskDelegatesKeyedByTaskIdentifier代理,通过这个唯一对应来处理相对应的代理方法.
	self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init];

	//初始化对象锁,用来处理多线程对可变字典mutableTaskDelegatesKeyedByTaskIdentifier操作时的线程安全
	//
	self.lock = [[NSLock alloc] init];
	self.lock.name = AFURLSessionManagerLockName;

	//这个获取session对应的未完成的task,那么在初始化时,获取的数组应该是空的才对.
	//不甚理解,后来在学习过程中,看到一个大神说的,当程序从后台回到前台,防止重新初始化先前后台未完成的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;
}

我们完成了初始化之后,下面来看看请求方法

- (NSURLSessionDataTask *)GET:(NSString *)URLString
               parameters:(id)parameters
                 progress:(void (^)(NSProgress * _Nonnull))downloadProgress
                  success:(void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))success
                  failure:(void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure {
	//调用对象方法创建task
	NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"GET"
                                                    URLString:URLString
                                                   parameters:parameters
                                               uploadProgress:nil
                                             downloadProgress:downloadProgress
                                                      success:success
                                                      failure:failure];
	//开始请求
	[dataTask resume];

	return dataTask;
}
//AFHTTPSessionManager中生成task任务的对象方法
- (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 {
	/**
	此处是将Method&url&parameters等参数转化成一个NSMutableURLRequest
	*/
	NSError *serializationError = nil;
	NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:&serializationError];
	if (serializationError) {
    	if (failure) {
    		//如果有completionQueue,则从该队列回调failure;没有completionQueue,则从主队列回调
        	dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
            	failure(nil, serializationError);
        	});
    	}

    	return nil;
	}

	__block NSURLSessionDataTask *dataTask = nil;
	//请求父类方法,最终生成任务task实例,并且在completionHandler中回调传入的failure和success.
	dataTask = [self dataTaskWithRequest:request
                      uploadProgress:uploadProgress
                    downloadProgress:downloadProgress
                   completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
    	if (error) {
        	if (failure) {
            	failure(dataTask, error);
        	}
    	} else {
        	if (success) {
            	success(dataTask, responseObject);
        	}
    	}
	}];

	return dataTask;
}
/**
此方法里首先是使用requestSerializer生成request;
然后根据request调用父类的方法生成最终的task.
*/

接下来我们首先看看生成request的方法的实现

- (NSMutableURLRequest *)requestWithMethod:(NSString *)method
                             URLString:(NSString *)URLString
                            parameters:(id)parameters
                                 error:(NSError *__autoreleasing *)error {
    //断言,debug时,缺少这两个参数会在此处crash.
	NSParameterAssert(method);
	NSParameterAssert(URLString);

	NSURL *url = [NSURL URLWithString:URLString];
	//根据URLString生成url,如果url不存在,则crash
	NSParameterAssert(url);

	NSMutableURLRequest *mutableRequest = [[NSMutableURLRequest alloc] initWithURL:url];
	mutableRequest.HTTPMethod = method;
	
	/**
	AFHTTPRequestSerializerObservedKeyPaths() C函数,
	存储了需要观察的path:allowsCellularAccess, cachePolicy, HTTPShouldHandleCookies, HTTPShouldUsePipelining, networkServiceType, timeoutInterval;
	*/
	
	for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) {
	
		/**
		mutableObservedChangedKeyPaths:集合,
		AFHTTPRequestSerializer的一个属性,在AFHTTPRequestSerializer对象init时,
		创建了mutableObservedChangedKeyPaths这个集合
		并且为AFHTTPRequestSerializerObservedKeyPaths()该方法获取到的属性名添加了观察者
		此为集合初始化及添加观察者:
		self.mutableObservedChangedKeyPaths = [NSMutableSet set];
		for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) {
    		if ([self respondsToSelector:NSSelectorFromString(keyPath)]) {
        	[self addObserver:self forKeyPath:keyPath options:NSKeyValueObservingOptionNew context:AFHTTPRequestSerializerObserverContext];
    		}
		}
		//观察者:
		- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(__unused id)object change:(NSDictionary *)change
                   context:(void *)context {
			if (context == AFHTTPRequestSerializerObserverContext) {
				//观察者监听到属性的set方法被调用后,先判断属性值是否为null,为null则移除,否则添加到集合中
    			if ([change[NSKeyValueChangeNewKey] isEqual:[NSNull null]]) {
        			[self.mutableObservedChangedKeyPaths removeObject:keyPath];
    			} else {
        			[self.mutableObservedChangedKeyPaths addObject:keyPath];
    			}
			}
		}
		*/
		
    	if ([self.mutableObservedChangedKeyPaths containsObject:keyPath]) {
    		//此时,将自己监听到设置过的属性值赋值给Request
        	[mutableRequest setValue:[self valueForKeyPath:keyPath] forKey:keyPath];
    	}
	}
	/**
	requestBySerializingRequest:withParameters:error:该方法将传入的parameters参数编码,拼接到request中
	涉及到parameters参数的解析方式以及根据请求方式对请求体的设置.
	*/
	mutableRequest = [[self requestBySerializingRequest:mutableRequest withParameters:parameters error:error] mutableCopy];

	return mutableRequest;
}

/**
C函数,存储了NSUrlRequest的属性名,
在上面的方便中,遍历这个数组,监听这些属性值的改变,并且对应的给这些属性赋值
*/

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;
}

以上,我们就获取到了request,接下来我们看核心类AFURLSessionManger的生成task任务的方法

- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
                           uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgressBlock
                         downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock
                        completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject,  NSError * _Nullable error))completionHandler {

	__block NSURLSessionDataTask *dataTask = nil;
	//对iOS8.0以下的线程安全处理
	//使用同步任务串行队列确保传值正确,并且创建的taskIdentifiers值唯一,后面要使用taskIdentifiers与delegate唯一对应.
	url_session_manager_create_task_safely(^{
    	dataTask = [self.session dataTaskWithRequest:request];
	});
	
	[self addDelegateForDataTask:dataTask uploadProgress:uploadProgressBlock downloadProgress:downloadProgressBlock completionHandler:completionHandler];

	return dataTask;
}


static void url_session_manager_create_task_safely(dispatch_block_t block) {
	if (NSFoundationVersionNumber < NSFoundationVersionNumber_With_Fixed_5871104061079552_bug) {
    	// Fix of bug
    	// Open Radar:http://openradar.appspot.com/radar?id=5871104061079552 (status: Fixed in iOS8)
    	// Issue about:https://github.com/AFNetworking/AFNetworking/issues/2093
    	dispatch_sync(url_session_manager_creation_queue(), block);
	} else {
    	block();
	}
}

static dispatch_queue_t url_session_manager_creation_queue() {
	static dispatch_queue_t af_url_session_manager_creation_queue;
	static dispatch_once_t onceToken;
	dispatch_once(&onceToken, ^{
    	af_url_session_manager_creation_queue = dispatch_queue_create("com.alamofire.networking.session.manager.creation", DISPATCH_QUEUE_SERIAL);
	});

	return af_url_session_manager_creation_queue;
}
//接下来设置task与delegate关联
- (void)addDelegateForDataTask:(NSURLSessionDataTask *)dataTask
            uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgressBlock
          downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock
         completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler {
    
	AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] initWithTask:dataTask];
	//代理中拥有AFURLSessionManager属性
	delegate.manager = self;
	delegate.completionHandler = completionHandler;

	dataTask.taskDescription = self.taskDescriptionForSessionTasks;
	//关联任务和代理
	[self setDelegate:delegate forTask:dataTask];
	//上传于下载进度回调
	delegate.uploadProgressBlock = uploadProgressBlock;
	delegate.downloadProgressBlock = downloadProgressBlock;
}

- (void)setDelegate:(AFURLSessionManagerTaskDelegate *)delegate
        forTask:(NSURLSessionTask *)task {
	NSParameterAssert(task);
	NSParameterAssert(delegate);
	//加锁,保证线程安全,mutableTaskDelegatesKeyedByTaskIdentifier为可变字典.
	[self.lock lock];
	//用taskIdentifier与delegate建立对应关系,且taskIdentifier唯一
	self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate;
	//发送任务开启暂停的通知
	[self addNotificationObserverForTask:task];
	[self.lock unlock];
}

到这里,任务创建成功,并且与代理建立对应关系,然后task开始请求网络,还记得我们初始化方法中的:self.session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue];是的,我们又回到了这里,在此处,我们把self(即AFUrlSessionManager)设置为task的delegate,请求开始后,就会调用NSURLSession的相关代理,AFURLSessionManager的声明中:@interface AFURLSessionManager : NSObject <NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate, NSSecureCoding, NSCopying>,AFURLSessionManager遵守了NSURLSession的代理.

剩下的就是一堆代理的回调以及AFNetworking自定义的回调请求结果的block,看着晕,麻烦自行查看啦!谢谢!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值