ios 获取当前的调度队列?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17475002/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 00:13:53  来源:igfitidea点击:

Get current dispatch queue?

iphoneiosobjective-cgrand-central-dispatchdispatch

提问by Andrew

I have a method which should support being called from any queue, and should expect to.

我有一个方法应该支持从任何队列中调用,并且应该支持。

It runs some code in a background thread itself, and then uses dispatch_get_main_queuewhen it returns a value to its block argument.

它在后台线程本身中运行一些代码,然后dispatch_get_main_queue在它返回一个值给它的块参数时使用。

I don't want it to force it onto the main queue if it wasn't when it entered the method. Is there a way to get a pointer to the current dispatch queue?

如果它不是在进入方法时,我不希望它强制进入主队列。有没有办法获得指向当前调度队列的指针?

采纳答案by Michael Dautermann

You do have the option of "dispatch_get_current_queue()", however the iOS 6.1 SDK defines this API with these disclaimers:

您确实可以选择" dispatch_get_current_queue()",但是 iOS 6.1 SDK 使用以下免责声明定义了此 API:

"Recommended for debugging and logging purposes only:"

Recommended for debugging and logging purposes only:

and

"This function is deprecated and will be removed in a future release.".

This function is deprecated and will be removed in a future release.”。

Here's another related question with some alternativesyou can consider if you want code that's future-proof.

这是另一个相关问题,如果您想要面向未来的代码,您可以考虑一些替代方案

回答by Palle

If you are working with an NSOperationQueue, it can provide the current dispatch queue for you.

如果您正在使用NSOperationQueue,它可以为您提供当前的调度队列。

NSOperationQueue has the class function [NSOperationQueue currentQueue], which returns the current queue as a NSOperationQueue object. To get the dispatch queue object you can use [NSOperationQueue currentQueue].underlyingQueue, which returns your currrent queue as a dispatch_queue_t.

NSOperationQueue 具有类 function [NSOperationQueue currentQueue],它将当前队列作为 NSOperationQueue 对象返回。要获取您可以使用的调度队列对象[NSOperationQueue currentQueue].underlyingQueue,它将您当前的队列作为dispatch_queue_t.

Swift 3:

斯威夫特 3:

if let currentDispatch = OperationQueue.current?.underlyingQueue {
    print(currentDispatch)
}

- works for main queue!

- 适用于主队列!

回答by ipmcc

With the deprecation of dispatch_get_current_queue()there is effectively no way to know what queue you're executing on. If you peruse the GCD sources, you'll eventually see that this is because there may be multiple answers to the question "what queue am I executing on?" (Because queues eventually target one of the global queues, etc.)

由于弃用了dispatch_get_current_queue(),实际上无法知道您正在执行哪个队列。如果您仔细阅读GCD 源代码,您最终会发现这是因为“我在哪个队列上执行?”这个问题可能有多种答案。(因为队列最终以全局队列之一为目标,等等)

If you want to guarantee that a future block is run on a specific queue, then the only way is to make your API accept a queue as a parameter along with the completion block. This lets the caller decide where the completion gets executed.

如果您想保证未来块在特定队列上运行,那么唯一的方法是让您的 API 接受队列作为参数以及完成块。这让调用者决定在何处执行完成。

If simply knowing whether the caller is on the main thread or not is enough, you can use +[NSThread isMainThread]to find out. In the common case, all blocks executing on the main GCD queue will be executing on the main thread. (One exception to this rule is if your application uses dispatch_main()in lieu of a main run loop, you will have to use dispatch_get_specificand friends to detect with certainty that you are executing on the main queue -- this is a comparatively rare circumstance.) More commonly, note that not all code that executes on the main thread executes on the main queue via GCD; GCD is subordinate to the main thread runloop. For your specific case it sounds like that might be enough.

如果仅仅知道调用者是否在主线程上就足够了,您可以使用+[NSThread isMainThread]来找出。在一般情况下,在主 GCD 队列上执行的所有块都将在主线程上执行。(此规则的一个例外是,如果您的应用程序使用dispatch_main()代替主运行循环,您将不得不使用dispatch_get_specific它的朋友来确定您正在主队列上执行——这是一种相对罕见的情况。)更常见,注意并不是所有在主线程上执行的代码都通过GCD在主队列上执行;GCD 从属于主线程 runloop。对于您的具体情况,这听起来可能就足够了。

回答by ambientlight

With the deprecation of dispatch_get_current_queue()you cannot directly get a pointer to the queue you are running on, however you do can get the current queue's labelby calling dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL)and that does give you some flexibility.

随着弃用,dispatch_get_current_queue()您无法直接获得指向您正在运行的队列的指针,但是您可以通过调用获取当前队列的标签dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL),这确实给了您一些灵活性。

You can always check if you are on that specific queue just by comparing their labels, so in your case if you don't want to force it on main queue, when you entered the method you can just utilize the following flag:

您始终可以通过比较它们的标签来检查您是否在该特定队列中,因此在您的情况下,如果您不想将其强制在主队列上,则在进入该方法时,您可以使用以下标志:

let isOnMainQueue = (dispatch_queue_get_label(dispatch_get_main_queue()) == dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL))

If you are running on the global queue, you will respectfully get the queue's label associated with it's QOS type, which can be one of the following:

如果您在全局队列上运行,您将获得与其 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) 

And then you can use dispatch_get_global_queue(qos_class_self(), 0)which will give you back that same global queue you are running on.

然后您可以使用dispatch_get_global_queue(qos_class_self(), 0)which 将返回您正在运行的相同全局队列。

But I believe Apple particularly discourages us from bounding the logic to the queue we got called on, so better utilising this for exclusively debugging purposes.

但是我相信 Apple 特别不鼓励我们将逻辑绑定到我们被调用的队列,因此最好将其用于专门的调试目的。

回答by Vasily Bodnarchuk

Based on Oleg Barinovanswer

基于奥列格·巴里诺夫的回答

Details

细节

  • Swift 5.1, Xcode 11.3.1
  • 斯威夫特 5.1,Xcode 11.3.1

Solution

解决方案

import Foundation

// MARK: private functionality

extension DispatchQueue {

    private struct QueueReference { weak var queue: DispatchQueue? }

    private static let key: DispatchSpecificKey<QueueReference> = {
        let key = DispatchSpecificKey<QueueReference>()
        setupSystemQueuesDetection(key: key)
        return key
    }()

    private static func _registerDetection(of queues: [DispatchQueue], key: DispatchSpecificKey<QueueReference>) {
        queues.forEach { 
DispatchQueue.currentQueueLabel
DispatchQueue.current
DispatchQueue.global(qos: .default) == DispatchQueue.current
DispatchQueue.main === DispatchQueue.current
.setSpecific(key: key, value: QueueReference(queue:
let queue = DispatchQueue(label: "queue-sample")
DispatchQueue.registerDetection(of: queue)
if DispatchQueue.current == queue { ... }
)) } } private static func setupSystemQueuesDetection(key: DispatchSpecificKey<QueueReference>) { let queues: [DispatchQueue] = [ .main, .global(qos: .background), .global(qos: .default), .global(qos: .unspecified), .global(qos: .userInitiated), .global(qos: .userInteractive), .global(qos: .utility) ] _registerDetection(of: queues, key: key) } } // MARK: public functionality extension DispatchQueue { static func registerDetection(of queue: DispatchQueue) { _registerDetection(of: [queue], key: key) } static var currentQueueLabel: String? { current?.label } static var current: DispatchQueue? { getSpecific(key: key)?.queue } }

Usage

用法

Detect system queue

检测系统队列

func subTest(queue: DispatchQueue) {
    queue.async {
        print("--------------------------------------------------------")
        print("queue label: \(DispatchQueue.currentQueueLabel ?? "nil")")
        print("print DispatchQueue.current: \(String(describing: DispatchQueue.current))")
        print("print queue == DispatchQueue.current: \(queue == DispatchQueue.current)")
        print("print queue === DispatchQueue.current: \(queue === DispatchQueue.current)")
        print("DispatchQueue.main == DispatchQueue.current: \(DispatchQueue.main == DispatchQueue.current)\n")
    }
}

func test() {
    subTest(queue: DispatchQueue.main)
    sleep(1)
    subTest(queue: DispatchQueue.global(qos: .default))
    sleep(1)
    subTest(queue: DispatchQueue.global(qos: .utility))
    sleep(1)

    let queue = DispatchQueue(label: "queue-sample")
    DispatchQueue.registerDetection(of: queue)
    subTest(queue: queue)
    sleep(1)
}

test()
DispatchQueue.global(qos: .default).async {
    test()
}

Detect custom queue

检测自定义队列

--------------------------------------------------------
queue label: com.apple.root.default-qos
print DispatchQueue.current: Optional(<OS_dispatch_queue_global: com.apple.root.default-qos[0x7fff89eb47c0] = { xref = -2147483648, ref = -2147483648, sref = 1, target = [0x0], width = 0xfff, state = 0x0060000000000000, in-barrier}>)
print queue == DispatchQueue.current: true
print queue === DispatchQueue.current: true
DispatchQueue.main == DispatchQueue.current: false

--------------------------------------------------------
queue label: com.apple.root.utility-qos
print DispatchQueue.current: Optional(<OS_dispatch_queue_global: com.apple.root.utility-qos[0x7fff89eb46c0] = { xref = -2147483648, ref = -2147483648, sref = 1, target = [0x0], width = 0xfff, state = 0x0060000000000000, in-barrier}>)
print queue == DispatchQueue.current: true
print queue === DispatchQueue.current: true
DispatchQueue.main == DispatchQueue.current: false

--------------------------------------------------------
queue label: queue-sample
print DispatchQueue.current: Optional(<OS_dispatch_queue_serial: queue-sample[0x600000275780] = { xref = 7, ref = 3, sref = 2, target = com.apple.root.default-qos.overcommit[0x7fff89eb4840], width = 0x1, state = 0x0060002500000b01, enqueued, max qos 5, draining on 0xb03, in-barrier}>)
print queue == DispatchQueue.current: true
print queue === DispatchQueue.current: true
DispatchQueue.main == DispatchQueue.current: false

--------------------------------------------------------
queue label: com.apple.main-thread
print DispatchQueue.current: Optional(<OS_dispatch_queue_main: com.apple.main-thread[0x7fff89eb43c0] = { xref = -2147483648, ref = -2147483648, sref = 1, target = com.apple.root.default-qos.overcommit[0x7fff89eb4840], width = 0x1, state = 0x001ffe9000000300, dirty, in-flight = 0, thread = 0x303 }>)
print queue == DispatchQueue.current: true
print queue === DispatchQueue.current: true
DispatchQueue.main == DispatchQueue.current: true

--------------------------------------------------------
queue label: com.apple.main-thread
print DispatchQueue.current: Optional(<OS_dispatch_queue_main: com.apple.main-thread[0x7fff89eb43c0] = { xref = -2147483648, ref = -2147483648, sref = 1, target = com.apple.root.default-qos.overcommit[0x7fff89eb4840], width = 0x1, state = 0x001ffe9000000300, dirty, in-flight = 0, thread = 0x303 }>)
print queue == DispatchQueue.current: true
print queue === DispatchQueue.current: true
DispatchQueue.main == DispatchQueue.current: true

--------------------------------------------------------
queue label: com.apple.root.default-qos
print DispatchQueue.current: Optional(<OS_dispatch_queue_global: com.apple.root.default-qos[0x7fff89eb47c0] = { xref = -2147483648, ref = -2147483648, sref = 1, target = [0x0], width = 0xfff, state = 0x0060000000000000, in-barrier}>)
print queue == DispatchQueue.current: true
print queue === DispatchQueue.current: true
DispatchQueue.main == DispatchQueue.current: false

--------------------------------------------------------
queue label: com.apple.root.utility-qos
print DispatchQueue.current: Optional(<OS_dispatch_queue_global: com.apple.root.utility-qos[0x7fff89eb46c0] = { xref = -2147483648, ref = -2147483648, sref = 1, target = [0x0], width = 0xfff, state = 0x0060000000000000, in-barrier}>)
print queue == DispatchQueue.current: true
print queue === DispatchQueue.current: true
DispatchQueue.main == DispatchQueue.current: false

--------------------------------------------------------
queue label: queue-sample
print DispatchQueue.current: Optional(<OS_dispatch_queue_serial: queue-sample[0x60000027a280] = { xref = 7, ref = 3, sref = 2, target = com.apple.root.default-qos.overcommit[0x7fff89eb4840], width = 0x1, state = 0x0060002500000b01, enqueued, max qos 5, draining on 0xb03, in-barrier}>)
print queue == DispatchQueue.current: true
print queue === DispatchQueue.current: true
DispatchQueue.main == DispatchQueue.current: false

Sample

样本

Do not forget to paste the solution code here.

不要忘记在此处粘贴解决方案代码。

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)

Result

结果

@interface NSObject <NSObject> { ... }

回答by Oleg Barinov

Based on the source from SQLite.swift.
If you want to check whether you're on own special dispatch queue:

基于SQLite.swift的来源。
如果您想检查您是否在自己的特殊调度队列中:

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;
}

回答by André Fratelli

As an alternative approach to this NSOBject's method performSelector:withObject:afterDelay:dispatches the call on the current thread's run loop. According to the docs:

作为 thisNSOBject方法的替代方法performSelector:withObject:afterDelay:在当前线程的运行循环上调度调用。根据文档:

This method sets up a timer to perform the aSelector message on the current thread's run loop.

该方法设置了一个计时器来在当前线程的运行循环上执行 aSelector 消息。

Obviously I'm suggesting using this with a delay of zero, which, according to the docs again:

显然,我建议在延迟为零的情况下使用它,根据文档再次:

Specifying a delay of 0 does not necessarily cause the selector to be performed immediately. The selector is still queued on the thread's run loop and performed as soon as possible.

指定延迟 0 不一定会导致选择器立即执行。选择器仍然在线程的运行循环中排队并尽快执行。

Unfortunately it requires exactly one argument, so some workarounds might be needed if your method takes more or less.

不幸的是,它只需要一个参数,因此如果您的方法需要更多或更少的时间,则可能需要一些解决方法。

One other thing I noted is that this method is not available for protocols, but implementations alone. This is due to this method living in an NSObjectcategory, and not in the NSObjectinterface (see PS below). This can easily be fixed by casting to id.

我注意到的另一件事是这种方法不适用于协议,而只能用于实现。这是因为这个方法存在于一个NSObject类别中,而不是在NSObject界面中(见下面的 PS)。这可以通过强制转换为 轻松解决id

PS: Two different NSObjects exist, a protocol and an implementation. Notice NSObjectdeclaration:

PS:NSObject存在两个不同的s,一个协议和一个实现。通知NSObject声明:

/**
 * @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;
}

It might seem odd, but one is being declared (after @interface) and the other one is a previously declared protocol (between <and >). When declaring a protocol that extends NSObject (ie., @protocol Foo <NSObject>) the protocol inherits the methods from the later, but not the former. Eventually the protocol is implemented by some class that inherits from the NSObjectimplementation, so all instances inheriting from the NSObjectimplementation still holds. But I'm getting off topic.

这可能看起来很奇怪,但一个是被声明的(在 之后@interface),另一个是之前声明的协议(在<和之间>)。当声明一个扩展 NSObject(即@protocol Foo <NSObject>)的协议时,该协议继承了后者的方法,而不是前者。最终协议是由从NSObject实现继承的某个类实现的,所以从NSObject实现继承的所有实例仍然有效。但我跑题了。

回答by johnrechd

There is actually still a way to compare the queue.

其实还是有办法比较队列的。

When you set up your queue, make sure that you add the label. For my purposes, I have a shared queue that is used for accessing a database to prevent database locking. In my DB.m file I have defined the shared queue function like:

设置队列时,请确保添加标签。出于我的目的,我有一个共享队列,用于访问数据库以防止数据库锁定。在我的 DB.m 文件中,我定义了共享队列函数,如:

const char *currentLabel = dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL);

The shared db transaction queue is used locally in the file to dispatch all executions to the database. However, there is also a public accessor on this to allow dispatching entire transactions to the database. So internally, if a DB access method is called from within the transaction queue, we need to dispatch internally on a different queue (all synchronous dispatches). So internally, I always dispatch on the proper queue by using the below getter.

共享 db 事务队列在文件中本地使用,以将所有执行分派到数据库。但是,还有一个公共访问器,允许将整个事务分派到数据库。所以在内部,如果从事务队列内部调用数据库访问方法,我们需要在不同的队列内部调度(所有同步调度)。所以在内部,我总是使用下面的 getter 在适当的队列上调度。

// 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();
}

Hopefully this helps. Sorry for the long example. The Gist of it is that you can use

希望这会有所帮助。对不起,这个例子太长了。它的要点是你可以使用

let queueName = dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL)

to get the label of the current queue and compare to a defined label.

获取当前队列的标签并与定义的标签进行比较。

回答by user1687195

I have the same functional requirements the original post mentions. You should be able to call this async function on any queue, but if called on the main queue, then callback to the user on the main queue. I simply handle it like so:

我有原始帖子提到的相同功能要求。您应该能够在任何队列上调用此异步函数,但如果在主队列上调用,则回调到主队列上的用户。我只是像这样处理它:

##代码##

回答by vikas kumar jangir

To get the label of the current queue and compare to a defined label using.

获取当前队列的标签并使用定义的标签进行比较。

##代码##