У меня есть метод, который должен поддерживать вызов из любой очереди и должен ожидать. Он запускает некоторый код в фоновом потоке сам, а затем использует dispatch_get_main_queue, когда он возвращает значение для аргумента block. Я не хочу, чтобы он заставлял его на основную очередь, если это не было, когда он ввел метод. Есть ли способ получить указатель на текущую очередь отправки?
Получить текущую очередь отправки?
Ответ 1
 У вас есть опция  dispatch_get_current_queue(), однако SDK для iOS 6.1 определяет этот API со следующими оговорками:
 " Recommended for debugging and logging purposes only: "
а также
 This function is deprecated and will be removed in a future release. " This function is deprecated and will be removed in a future release. "
Вот еще один связанный вопрос с некоторыми альтернативами, которые вы можете рассмотреть, если хотите, чтобы код был ориентирован на будущее.
Ответ 2
При устаревании dispatch_get_current_queue() не существует способа узнать, в какой очереди вы выполняете. Если вы просмотрите источники GCD, вы, в конце концов, увидите, что это связано с тем, что может быть несколько ответов на вопрос "какую очередь я выполняю на?" (Поскольку очереди в конечном итоге нацелены на одну из глобальных очередей и т.д.)
Если вы хотите гарантировать, что будущий блок будет запущен в определенной очереди, единственный способ - заставить ваш API принимать очередь в качестве параметра вместе с блоком завершения. Это позволяет вызывающему абоненту решить, где выполняется завершение.
Если просто узнать, есть ли вызывающий объект в основном потоке или нет, вы можете использовать +[NSThread isMainThread], чтобы узнать. В общем случае все блоки, исполняемые в главной очереди GCD, будут выполняться в основном потоке. (Одно исключение из этого правила заключается в том, что если ваше приложение использует dispatch_main() вместо основного цикла запуска, вам нужно будет использовать dispatch_get_specific и друзей для уверенности в том, что вы выполняете в главной очереди - это сравнительно редкое обстоятельство.) Чаще всего обратите внимание, что не весь код, который выполняется в основном потоке, выполняется в главной очереди через GCD; GCD подчинен основной линии runloop. Для вашего конкретного случая кажется, что этого может быть достаточно.
Ответ 3
Если вы работаете с NSOperationQueue, он может предоставить вам текущую очередь отправки.
NSOperationQueue имеет функцию класса [NSOperationQueue currentQueue], которая возвращает текущую очередь в виде объекта NSOperationQueue. Чтобы получить объект очереди отправки, вы можете использовать [NSOperationQueue currentQueue].underlyingQueue, который возвращает вашу текущую очередь в виде dispatch_queue_t.
Свифт 3:
if let currentDispatch = OperationQueue.current?.underlyingQueue {
    print(currentDispatch)
}
- работает для основной очереди!
Ответ 4
С отменой dispatch_get_current_queue() вы не можете напрямую получить указатель на очередь, на которой вы работаете, однако  вы можете получить текущую метку очереди, вызвав dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL), и это дает вам гибкость.
Вы всегда можете проверить, находитесь ли вы в этой конкретной очереди, просто сравнивая их ярлыки, поэтому в вашем случае, если вы не хотите принуждать ее к основной очереди, при вводе метода вы можете просто использовать следующий флаг:
let isOnMainQueue = (dispatch_queue_get_label(dispatch_get_main_queue()) == dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL))
Если вы работаете в глобальной очереди, вы с уважением получите метку очереди, связанную с этим типом QOS, которая может быть одной из следующих:
com.apple.root.user-interactive-qos //qos_class_t(rawValue: 33)
com.apple.root.user-initiated-qos   //qos_class_t(rawValue: 25)
com.apple.root.default-qos          //qos_class_t(rawValue: 21)  
com.apple.root.utility-qos          //qos_class_t(rawValue: 17)
com.apple.root.background-qos       //qos_class_t(rawValue: 9) 
И затем вы можете использовать dispatch_get_global_queue(qos_class_self(), 0), который вернет вам ту же самую глобальную очередь, в которой вы работаете.
Но я считаю, что Apple особенно препятствует нам ограничивать логику в очередь, на которую нас вызвали, поэтому лучше использовать это для исключительно задач отладки.
Ответ 5
На самом деле есть способ сравнить очередь.
Когда вы настраиваете свою очередь, убедитесь, что вы добавили ярлык. Для моих целей у меня есть общая очередь, которая используется для доступа к базе данных для предотвращения блокировки базы данных. В моем файле DB.m я определил функцию общей очереди, например:
const char *kTransactionQueueLabel = "DB_TRANSACTION_DISPATCH_QUEUE";
+ (dispatch_queue_t)sharedDBTransactionQueue {
    static dispatch_queue_t sharedDBQueue = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedDBQueue = dispatch_queue_create(kTransactionQueueLabel, DISPATCH_QUEUE_SERIAL);
    });
    return sharedDBQueue;
}
Очередь транзакций shared db используется локально в файле для отправки всех исполнений в базу данных. Тем не менее, для этого есть и общедоступный аксессуар, который позволяет отправлять целые транзакции в базу данных. Поэтому внутренне, если из очереди транзакций вызывается метод доступа к БД, нам нужно отправлять внутренне в другую очередь (все синхронные рассылки). Поэтому я всегда отправляю нужную очередь, используя нижепользователь.
/**
 * @description Decide which queue to use - if we are already in a transaction, use the internal access queue, otherwise use the shared transaction queue.
 */
- (dispatch_queue_t)getProperQueueForExecution {
    const char *currentLabel = dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL);
    dispatch_queue_t sharedAccessQueue = [DB sharedDBTransactionQueue];
    if (strcmp(currentLabel, kTransactionQueueLabel) == 0) {
        sharedAccessQueue = [DB sharedInternalDBAccessQueue];
    }
    return sharedAccessQueue;
}
Надеюсь, это поможет. Извините за длинный пример. Суть в том, что вы можете использовать
const char *currentLabel = dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL);
чтобы получить метку текущей очереди и сравнить с определенной меткой.
Ответ 6
В качестве альтернативного подхода к этому методу NSOBject performSelector:withObject:afterDelay: отправляет вызов в текущий цикл выполнения потока. Согласно документам:
Этот метод устанавливает таймер для выполнения сообщения aSelector на текущий цикл выполнения потоков.
Очевидно, я предлагаю использовать это с задержкой нуля, которая, согласно документам снова:
Задание задержки 0 не обязательно приводит к тому, что селектор будет выполняется немедленно. Селектор по-прежнему поставлен в очередь на потоки и выполнить как можно скорее.
К сожалению, для этого требуется ровно один аргумент, поэтому некоторые методы могут понадобиться, если ваш метод принимает больше или меньше.
Еще одна вещь, которую я заметил, заключается в том, что этот метод недоступен для протоколов, но только для реализации. Это связано с тем, что этот метод живет в категории NSOBject, а не в интерфейсе NSOBject (см. Ниже). Это можно легко устранить, нажав на id.
PS: Существуют два разных NSOBject, протокол и реализация. Уведомление NSOBject:
@interface NSObject <NSObject> { ... }
Может показаться странным, но объявляется (после @interface), а другой - ранее объявленным протоколом (между < и >). При объявлении протокола, который расширяет NSObject (т.е., @protocol Foo <NSObject>), протокол наследует методы от более поздней, но не первой. В конечном итоге протокол реализуется некоторым классом, который наследует реализацию NSOBject, поэтому все экземпляры, наследующие от реализации NSOBject, все еще сохраняются. Но я ухожу от темы.
Ответ 7
 Основано на источнике из SQLite.swift. 
 Если вы хотите проверить, находитесь ли вы в собственной специальной очереди отправки:
class Worker {
    private static let queueKey = DispatchSpecificKey<Int>()
    private lazy var queueContext = unsafeBitCast(self, to: Int.self)
    private lazy var queue: DispatchQueue = {
        let value = DispatchQueue(label: "com.example.App.Worker")
        value.setSpecific(key: Worker.queueKey, value: queueContext)
        return value
    }()
    func test(x: Int) -> Int {
        return dispatchSync {
            return x > 2 ? test(x: x - 1) * x : x
        }
    }
    private func dispatchSync<T>(_ block: () throws -> T) rethrows -> T {
        if DispatchQueue.getSpecific(key: Worker.queueKey) != queueContext {
            return try queue.sync(execute: block)
        }
        return try block()
    }
}
let worker = Worker()
worker.test(x: 5)
		Ответ 8
У меня те же функциональные требования, что и оригинальные сообщения. Вы должны иметь возможность вызвать эту функцию async в любой очереди, но если она вызвана в основной очереди, то обратный вызов пользователю в главной очереди. Я просто обрабатываю его так:
// cache value for if we should callback on main queue
BOOL callbackOnMT = [NSThread isMainThread];
// ...
// ... do async work...
// ...
if (callbackOnMT && ![NSThread isMainThread]){
    dispatch_async(dispatch_get_main_queue(), ^{
        // callback to user on main queue
        // as they called this function on main queue
        callbackToUser();
    });
}
else{
    // callback to user on our current queue
    // as they called this function on a non-main queue
    callbackToUser();
}
		Ответ 9
Чтобы получить метку текущей очереди и сравнить с определенной меткой, используйте.
let queueName = dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL)