Хобрук: Ваш путь к мастерству в программировании

Как получить текущее имя очереди в 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. Как теперь получить имя очереди?

18.09.2016


Ответы:


1

Теперь DispatchQueue имеет свойство label.

Метка, которую вы присвоили очереди отправки во время создания.

var label: String { get } 

Кажется, он существовал с самого начала, возможно, не был раскрыт через общедоступный API.

macOS 10.10+

И, пожалуйста, используйте это только для получения удобочитаемых этикеток. Не идентифицировать каждый GCDQ.

Если вы хотите проверить, работает ли ваш код на определенном GCDQ, вы можете использовать функция dispatchPrecondition(...).

16.06.2020
  • @yuchen-zhong Это отвечает на вопрос? Я знаю, что это может быть полезно, но больше нет способа получить текущую очередь. 21.07.2020
  • @Klaas Получение AFAIK, получение текущего объекта очереди запрещено и настоятельно не рекомендуется. Я думаю, что есть несколько основных намерений... 22.07.2020
  • Я знаю, но ОП попросил об этом. Есть ли причина не использовать его для целей отладки? (Мне известно о developer.apple.com/documentation/dispatch/ ) 23.07.2020

  • 2

    Как отметил Брент Ройал-Гордон в своем сообщение на lists.swift.org — это дыра в текущем дизайне, но вы можете использовать этот ужасный обходной путь.

    func currentQueueName() -> String? {
        let name = __dispatch_queue_get_label(nil)
        return String(cString: name, encoding: .utf8)
    }
    
    01.10.2016
  • Только что попробовал решение, но для выполнения одной строки требуется дополнительное время, например 1-2 секунды. Разве не так..?? 11.04.2018

  • 3

    Если вам не нравятся небезопасные указатели и c-строки, есть другое безопасное решение:

    if let currentQueueLabel = OperationQueue.current?.underlyingQueue?.label {
        print(currentQueueLabel)
        // Do something...
    }
    

    Я не знаю случаев, когда currentQueueLabel будет nil.

    31.07.2017
  • Если очередь создается не нами, то какая будет метка? А вы видели этот вопрос? stackoverflow.com/questions/37952262 Это связано? @келин 31.07.2017
  • 1. Метка будет что-то вроде com.apple.main-thread. 2. Речь идет о тестировании и это вполне по теме, но прямого ответа на ваш вопрос нет. 31.07.2017
  • Это решение не работает правильно. Для той же очереди OperationQueue.current?.underlyingQueue?.label возвращает com.apple.main-thread, а String(cString: __dispatch_queue_get_label(nil), encoding: .utf8) возвращает myDispatchQueueLabel. 29.08.2017
  • В Xcode 9 и iOS 11 это не работает. Предпочтение __dispatch_queue_get_label(nil) 09.11.2017
  • Согласно документам Apple, если вы в настоящее время не находитесь в контексте операции, то current почти наверняка вернет ноль. 12.09.2018
  • @jakehawken, я пробовал. Я просто вставил print(OperationQueue.current) внутрь didFinishLaunchingWithOptions, а current не был равен нулю. Это было похоже на: <NSOperationQueue: 0x14cd38dd0>{name = 'NSOperationQueue Main Queue'}. Так что, наверное, все внутри контекста какой-то Операции. 13.09.2018
  • @kelin Я приятно удивлен, услышав это! Я основывал свое заявление на документации Apple. Хотя я рад это слышать. Хорошо знать! 14.09.2018
  • Это работает только для очередей отправки, которые были созданы специально для очередей операций, и, кроме того, срабатывает только в том случае, если эти очереди отправки в данный момент активны, потому что их очередь операций активно выполняет операцию. Если какое-либо из этих условий не выполняется, вы получите метку nil. Показательный пример: ваши собственные очереди отправки или ваш собственный блок во время отправки в любую очередь. 19.05.2019

  • 4

    Этот метод будет работать как для OperationQueue, так и для DispatchQueue.

    func printCurrnetQueueName()
    {
        print(Thread.current.name!)
    } 
    
    11.04.2018

    5

    Вот класс-оболочка, обеспечивающий некоторую безопасность (исправлено здесь):

    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's 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)
        }
    
    }
    
    25.02.2019
  • Как правило, создавать DispatchSpecificKey в качестве переменной экземпляра небезопасно. Ключи сравниваются по их адресу в памяти, если вы создаете и освобождаете несколько ключей, они могут в конечном итоге использовать один и тот же указатель. См. мой пост по этому вопросу: tom.lokhorst.eu /2018/02/ 26.02.2019
  • Интересно, спасибо @TomLokhorst! Здесь предпочтительнее угадать статическую константу, поскольку они потокобезопасны. 28.02.2019

  • 6

    Это работает лучше всего для меня:

    /// 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
            }
        }
    }
    
    12.10.2017
    Новые материалы

    Введение в контекст React
    В этом посте мы поговорим о Context API, который был представлен в React 16, и о том, как вы можете их использовать. Что такое контекст? Глядя на определение из react docs , оно..

    Шлюз с лицензией OSS, совместимый с Apollo Federation v2, появится в WunderGraph
    Сегодня мы рады сообщить, что мы сотрудничаем с поддерживаемой YC Tailor Technologies, Inc. для внедрения Apollo Federation v2. Реализация будет лицензирована MIT (Engine) и Apache 2.0..

    Это оно
    Ну, я официально уволился с работы! На этой неделе я буду лихорадочно выполнять последние требования Думающего , чтобы я мог сосредоточиться на поиске работы. Что именно это значит?..

    7 полезных библиотек JavaScript, которые вы должны использовать в своем следующем проекте
    Усильте свою разработку JavaScript Есть поговорка «Не нужно изобретать велосипед». Библиотеки — лучший тому пример. Это поможет вам написать сложные и трудоемкие функции простым способом...

    Базовое руководство по переносу концепций обучения в глубокое обучение
    Обзор По мере того, как машинное обучение становится все более мощным и продвинутым, модели, обеспечивающие эту расширенную возможность, становятся все больше и начинают требовать огромного..

    C в C.R.U.D с использованием React-Redux
    Если вы использовали React, возможно, вы знакомы с головной болью, связанной с обратным потоком данных. Передача состояния реквизитам от родительских компонентов к дочерним компонентам может..

    5 обязательных элементов современного инструмента конвейера данных
    В цифровом мире предприятия используют конвейеры данных для перемещения, преобразования и хранения огромных объемов данных. Эти конвейеры составляют основу бизнес-аналитики и играют..