为什么 AFNetworking 2.6.3 要包装一个独立的线程?
Some important factors:
- NSOperationQueue 使用 GCD 创建线程
Operation queues use the Dispatch framework to initiate the execution of their operations. As a result, operations are always executed on a separate thread, regardless of whether they are designated as synchronous or asynchronous.
- NSURLConnection delegate 默认会使用调用时的线程进行回调
As such we can reason that the thread exists because at the time it was written we can see that making a thread and scheduling your connections on it was the only way to receive callbacks from
NSURLConnection
in the background while running in an asynchronousNSOperation
subclass.
当然,spawn 一个 thread 并不是解决 NSOperation + NSURLConnection 问题的唯一手段,NSURLConnection 本身通过引入 delegateQueue
来解决这个问题:
NSURLConnection* connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO]; [connection setDelegateQueue:[[NSOperationQueue alloc] init]]; [connection start];
为什么 SDWebImage 4.4.3 没有使用类似的设计?
这是因为 SDWebImage 4.4.3 与 AFNetworking 3.1.0 相同,是在 NSURLSession 的基础上进行的封装。NSURLSession 也引入了 NSURLConnection delegateQueue
的概念,并将其作为了线程回调问题的唯一手段。如果设置的 delegateQueue
为 nil,NSURLSession 会直接回调主线程。SDWebImage 作为一个视图层的框架,回调到主线程刚好满足它只有在主线程才能操作 UI 对象的需求。
- (void)createNewSessionWithConfiguration:(NSURLSessionConfiguration *)sessionConfiguration { [self cancelAllDownloads]; if (self.session) { [self.session invalidateAndCancel]; } sessionConfiguration.timeoutIntervalForRequest = self.downloadTimeout; /** * Create the session for this task * We send nil as delegate queue so that the session creates a serial operation queue for performing all delegate * method calls and completion handler calls. */ self.session = [NSURLSession sessionWithConfiguration:sessionConfiguration delegate:self delegateQueue:nil]; }
那么 AFNetworking 3.1.0 呢?
AFNetworking 3.1.0 也是在 NSURLSession 的基础上进行工作的。线程回调问题,AFNetworking 3.1.0 与 SDWebImage 4.4.3 相同,都是通过 delegateQueue
来解决的。
- (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; self.session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue]; // ... return self; }
另外,AFNetworking 3.1.0 并没有使用 NSOperationQueue。因为 NSURLSession 本身有它自己的并发控制,而 NSURLConnection 没有。这是另一个话题。
@interface NSURLSessionConfiguration : NSObject <NSCopying> // ... @property NSInteger HTTPMaximumConnectionsPerHost; // ... @end
- NSURLSession.h
这也是一个讨巧的设计,因为 AFHTTPSessionManager 引入了 baseURL
,这意味着 NSURLSession 的 HTTPMaximumConnectionsPerHost
与 AFHTTPSessionManager 本身的最大并发数是等价的。