判断是否为主队列
- 写法一
Apple 爸爸讲, label 只是作为 debug 的标志符号, 可能相同,也可能为空,并不代表任何含义。但是我们依旧可以使用它在某些特定的场景
extension DispatchQueue {
static var currentQueueLabel: String? {
let cString = __dispatch_queue_get_label(nil)
return String(cString: cString)
}
static var isMainQueue: Bool {
return currentQueueLabel == self.main.label
}
}
- 写法二
let specificKey = DispatchSpecificKey<String>()
let specificValue = "com.dumbass.mainQueue.specificValue"
DispatchQueue.main.setSpecific(key: specificKey, value: specificValue)
if DispatchQueue.getSpecific(key: specificKey) == specificValue {
}
safeAsync 理解
sd_webImage 中, 早期版本的 asyncSafe 方法如下:
#define dispatch_main_sync_safe(block)\
if ([NSThread isMainThread]) {\
block();\
} else {\
dispatch_sync(dispatch_get_main_queue(), block);\
}
#define dispatch_main_async_safe(block)\
if ([NSThread isMainThread]) {\
block();\
} else {\
dispatch_async(dispatch_get_main_queue(), block);\
}
这里有个 issue
Calling an API from a non-main queue that is executing on the main thread will lead to issues if the library (like VektorKit) relies on checking for execution on the main queue.
主要是说: 一个在主线程执行任务的非主队列, 调用了一个依赖于在主队列中派发的 api 时会有个 issue
当前版本的 safeAsync 定义:
#ifndef dispatch_queue_async_safe
#define dispatch_queue_async_safe(queue, block)\
if (strcmp(dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL), dispatch_queue_get_label(queue)) == 0) {\
block();\
} else {\
dispatch_async(queue, block);\
}
#endif
#ifndef dispatch_main_async_safe
#define dispatch_main_async_safe(block) dispatch_queue_async_safe(dispatch_get_main_queue(), block)
#endif
那么这里的 safe 体现在哪里呐?
- 相对于 async 方法这个判断在当前队列是指定(主)队列时, 能直接派发任务, 而不是加到队列尾部排队等待
- 相对于 sync 方法这个判断在当前队列是指定(主)队列时, 直接派发任务避免线程死锁
再看 Kingfisher 中为 DispatchQueue 添加了一个 safeAsync 方法
这里 if self === DispatchQueue.main && Thread.isMainThread
: 如果要在主队列派发任务, 并且当前线程是主线程的情况下会直接派发, 这里并没有避开上面提到的 issue
extension DispatchQueue {
// This method will dispatch the `block` to self.
// If `self` is the main queue, and current thread is main thread, the block
// will be invoked immediately instead of being dispatched.
func safeAsync(_ block: @escaping ()->()) {
if self === DispatchQueue.main && Thread.isMainThread {
block()
} else {
async { block() }
}
}
}
====================================
- 写法⼀
func safeAsync(_ execute: @escaping () -> Void) {
if DispatchQueue.currentQueueLabel == self.label {
execute(); return
}
async(execute: execute)
}
- 写法二
extension DispatchQueue {
struct DispachQueueSafety {
private init() {
DispatchQueue.main.setSpecific(key: specificKey, value: specificValue)
}
var isMainQueue: Bool {
return DispatchQueue.getSpecific(key: specificKey) == specificValue
}
func async(execute: @escaping () -> Void) {
isMainQueue ? execute() : DispatchQueue.main.async(execute: execute)
}
let specificKey = DispatchSpecificKey<String>()
let specificValue = "com.dumbass.mainQueue.specific"
static let `default` = DispachQueueSafety()
}
var safe: DispachQueueSafety {
return DispachQueueSafety.default
}
}
网友评论