AFNetworking 源码阅读

独奏

学习思考|2016-1-11|最后更新: 2023-2-23|
type
Post
status
Published
date
Jan 11, 2016
slug
summary
tags
iOS
category
学习思考
icon
password
AFNetworking 3.0 发布了,这个版本去除了 NSURLConnectionOperation,使用 NSURLSession 代替,于是,这个版本只支持 iOS 7以及以上版本,代码也相应的精简了不少,于是利用一周时间阅读了一下 AFNetworking 3.0 的源码。

技巧

#pragma clang diagnostic push #pragma clang diagnostic ignored "-Wgnu" //code #pragma clang diagnostic pop
使用 :? 符号,忽略编译器的警告

iOS bug fix

AFURLSessionManager.m
// 解决NSURLSessionTask 的 taskIdentifier 在并发的情况下不是唯一的 bug,苹果在 iOS8 的时候解决了这个 bug 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(); } }
AFURLSessionManager.h
/** Whether to attempt to retry creation of upload tasks for background sessions when initial call returns `nil`. `NO` by default. @bug As of iOS 7.0, there is a bug where upload tasks created for background tasks are sometimes `nil`. As a workaround, if this property is `YES`, AFNetworking will follow Apple's recommendation to try creating the task again. @see https://github.com/AFNetworking/AFNetworking/issues/1675 */ // iOS7.0 的一个 bug,当创建 后台的 upload task 的时候可能是 nil,这个值为 YES 的时候会尝试重新创建 @property (nonatomic, assign) BOOL attemptsToRecreateUploadTasksForBackgroundSessions;

多线程

dispatch_semaphore的使用

AFURLSessionManager.m 里面的 tasksForKeyPath: 方法,通过引入信号量的方式把NSURLSession的异步方法 getTasksWithCompletionHandler: 变成了同步方法
- (NSArray *)tasksForKeyPath:(NSString *)keyPath { __block NSArray *tasks = nil; // 这里是把本来异步的getTasksWithCompletionHandler方法变成了同步的方式了,通过引入信号量的方式,等待异步方法获取到tasks,然后再返回 dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); [self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) { if ([keyPath isEqualToString:NSStringFromSelector(@selector(dataTasks))]) { tasks = dataTasks; } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(uploadTasks))]) { tasks = uploadTasks; } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(downloadTasks))]) { tasks = downloadTasks; } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(tasks))]) { tasks = [@[dataTasks, uploadTasks, downloadTasks] valueForKeyPath:@"@unionOfArrays.self"]; } dispatch_semaphore_signal(semaphore); }]; dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); return tasks; }
上面代码中 @unionOfArrays.self 参考:http://nshipster.com/kvc-collection-operators/

作者声明二级指针

// 这是一个指向指针的指针,二级指针 // https://www.zhihu.com/question/35661618 static void *AFHTTPRequestSerializerObserverContext = &AFHTTPRequestSerializerObserverContext;
这里是为了做 KVO 的时候给 context 赋值,便于区分不同的 context,由于这个AFHTTPRequestSerializerObserverContext的内存地址是在编译的时候就决定了,所以这么声明确实可以保证 context 不同,是个比较讨巧的方式

static 方法

作者在多处使用 static 方法

参考 & 代码地址

边阅读边标注,阅读标注后的代码地址:AFNetworking 3.0
参考: