Dispatch Queue
通常,应用程序中编写的线程管理用的代码要在系统级实现。
无论编程人员如何努力编写管理线程的代码,在性能方面也不可能胜过XNU内核级所实现的GCD。
用于实现Dispatch Queue而使用的软件组件:
- libdispatch 提供技术:Dispatch Queue;
- Libc(pthreads) 提供技术:pthread_workqueue;
- XNU内核 提供技术:workqueue;
GCD的API全部为包含在libdispatch库中的C语言函数。
Dispatch Queue通过结构体和链表实现为FIFO队列。队列管理师通过dispatch_async函数所追加的Block。
Block先加入Dispatch Continuation这一dispatch_continuation_t类型结构体中,然后在加入FIFO队列中。该Dispatch Continuation用于记忆Block所属的Dispatch Group和其他一些信息,相当于一般常说的执行上下文。
dispatch_set_target_queue函数可以设置Dispatch Queue为另一个Dispatch Queue的目标。可以像串珠子一样,设定多个连接在一起的Dispatch Queue。在连接的最后必须设定为Main Dispatch Queue,或各种优先级的Global Dispatch Queue或是准备用于Serial Dispatch Queue的各种优先级的Global Dispatch Queue。
Main Dispatch Queue在RunLoop中执行Block。
Global Dispatch Queue有8种类型。
ARC、Blocks、GCD使用范例
实现从指定的URL下载数据,在另外的线程中解析该数据并在主线程中使用其解析结果:
NSString *url = @"https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fphoto.16pic.com%2F00%2F54%2F75%2F16pic_5475997_b.jpg&refer=http%3A%2F%2Fphoto.16pic.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1617284495&t=3bacab64a5d8233a37c94e2cc7f47492";
//在主线程中,从指定的url开始异步网络下载
NSURL *postUrl = [NSURL URLWithString:url];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:postUrl];
request.HTTPMethod = @"GET";
[request setTimeoutInterval:15];
request.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error)
{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^
{
//不妨碍主线程可长时间处理获取的数据
dispatch_async(dispatch_get_main_queue(), ^
{
//对界面进行反应处理
});
});
}];
[task resume];
[session finishTasksAndInvalidate];
Cocoa框架提供了用于异步网络通信的API,所以在网络编程中不可使用线程。务必使用用于异步网络通信的API。
我们基于NSURLSession封装的异步网络请求:
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
typedef void (^completeBlock_t) (NSData *data);
typedef void (^errorBlock_t) (NSError *error);
@interface ASyncURLSession : NSURLSession
{
/**
*由于ARC有效,所以以下的没有显示附加所有权修饰符的变量,
*全部为附有__strong修饰符的变量。
*/
NSMutableData *data;
completeBlock_t completeBlock_;
errorBlock_t errorBlock_;
}
+(id)request:(NSString *)requestURL
completeBlock:(completeBlock_t)completeBlock
errorBlock:(errorBlock_t)errorBlock;
-(id)initWithRequest:(NSString *)requestURL
completeBlock:(completeBlock_t)completeBlock
errorBlock:(errorBlock_t)errorBlock;
@end
NS_ASSUME_NONNULL_END