Как получить текущее имя очереди в swift 3
У нас есть такая функция в swift 2.2 для печати сообщения журнала с текущим текущим потоком:
func MyLog(_ message: String) {
if Thread.isMainThread {
print("[MyLog]", message)
} else {
let queuename = String(UTF8String: dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL))! // Error: Cannot convert value of type '()' to expected argument type 'DispatchQueue?'
print("[MyLog] [\(queuename)]", message)
}
}
Этот код больше не компилируется в swift 3.0. Как получить имя очереди сейчас?
Вопрос о том, как определить, где два потока - это один и тот же поток: Проверить правильность очереди отправки в Swift 3. В принятом ответе предлагается использовать setSpecific
для сопоставления метки с созданной очередью. Однако это не решает проблему, потому что мы хотим знать имя очереди. И очередь может не обязательно создаваться самим.
Ответы
Ответ 1
Как Brent Royal-Gordon, упомянутый в его сообщении на lists.swift.org, это отверстие в текущий дизайн, но вы можете использовать это ужасное обходное решение.
func currentQueueName() -> String? {
let name = __dispatch_queue_get_label(nil)
return String(cString: name, encoding: .utf8)
}
Ответ 2
Если вам не нравятся небезопасные указатели и c-строки, есть еще одно безопасное решение:
if let currentQueueLabel = OperationQueue.current?.underlyingQueue?.label {
print(currentQueueLabel)
// Do something...
}
Я не знаю случаев, когда currentQueueLabel
будет nil
.
Ответ 3
Вот класс-оболочка, который предлагает некоторую безопасность (пересмотрено здесь):
import Foundation
/// DispatchQueue wrapper that acts as a reentrant to a synchronous queue;
/// so callers to the 'sync' function will check if they are on the current
/// queue and avoid deadlocking the queue (e.g. by executing another queue
/// dispatch call). Instead, it will just execute the given code in place.
public final class SafeSyncQueue {
public init(label: String, attributes: DispatchQueue.Attributes) {
self.queue = DispatchQueue(label: label, attributes: attributes)
self.queueKey = DispatchSpecificKey<QueueIdentity>()
self.queue.setSpecific(key: self.queueKey, value: QueueIdentity(label: self.queue.label))
}
// MARK: - API
/// Note: this will execute without the specified flags if it on the current queue already
public func sync<T>(flags: DispatchWorkItemFlags? = nil, execute work: () throws -> T) rethrows -> T {
if self.currentQueueIdentity?.label == self.queue.label {
return try work()
} else if let flags = flags {
return try self.queue.sync(flags: flags, execute: work)
} else {
return try self.queue.sync(execute: work)
}
}
// MARK: - Private Structs
private struct QueueIdentity {
let label: String
}
// MARK: - Private Properties
private let queue: DispatchQueue
private let queueKey: DispatchSpecificKey<QueueIdentity>
private var currentQueueIdentity: QueueIdentity? {
return DispatchQueue.getSpecific(key: self.queueKey)
}
}
Ответ 4
Это работает лучше всего для меня:
/// The name/description of the current queue (Operation or Dispatch), if that can be found. Else, the name/description of the thread.
public func queueName() -> String {
if let currentOperationQueue = OperationQueue.current {
if let currentDispatchQueue = currentOperationQueue.underlyingQueue {
return "dispatch queue: \(currentDispatchQueue.label.nonEmpty ?? currentDispatchQueue.description)"
}
else {
return "operation queue: \(currentOperationQueue.name?.nonEmpty ?? currentOperationQueue.description)"
}
}
else {
let currentThread = Thread.current
return "UNKNOWN QUEUE on thread: \(currentThread.name?.nonEmpty ?? currentThread.description)"
}
}
public extension String {
/// Returns this string if it is not empty, else `nil`.
public var nonEmpty: String? {
if self.isEmpty {
return nil
}
else {
return self
}
}
}
Ответ 5
Этот метод будет работать как для Очереди операций, так и для Очереди отправки.
func printCurrnetQueueName()
{
print(Thread.current.name!)
}