ChatGPT解决这个技术问题 Extra ChatGPT

检查当前线程是否是主线程

有什么方法可以检查当前线程是否是 Objective-C 中的主线程?

我想做这样的事情。

  - (void)someMethod
  {
    if (IS_THIS_MAIN_THREAD?) {
      NSLog(@"ok. this is main thread.");
    } else {
      NSLog(@"don't call this method from other thread!");
    }
  }
从其他线程调用方法有什么问题?

L
Louis CAD

看看NSThread API documentation

有类似的方法

- (BOOL)isMainThread

+ (BOOL)isMainThread

+ (NSThread *)mainThread


d
dimohamdy

在 Swift3 中

if Thread.isMainThread {
    print("Main Thread")
}

b
boherna

如果你想在主线程上执行一个方法,你可以:

- (void)someMethod
{
    dispatch_block_t block = ^{
        // Code for the method goes here
    };

    if ([NSThread isMainThread])
    {
        block();
    }
    else
    {
        dispatch_async(dispatch_get_main_queue(), block);
    }
}

旧问题的答案可以受益于新答案与现有答案的不同之处的解释。
这是矫枉过正,如果某些工作必须在主线程上完成,那么检查你是否在主线程上是没有用的。只需执行NSOperationQueue.mainQueue().addOperationWithBlock { //your work here }
@Eric我同意,但是如果您想在主线程中立即执行该方法怎么办?在您的建议中,该方法总是被分派以便稍后通过主操作队列执行。
@boherna 正确,这是需要注意的。
@boherna 迟到的评论,但如果您在示例中使用 dispatch_sync() 而不是 dispatch_async(),您在评论中提出的观点会更加有力。
E
Eric

如果你想知道你是否在主线程上,你可以简单地使用调试器。在您感兴趣的行设置一个断点,当您的程序到达它时,调用它:

(lldb) thread info

这将显示有关您所在线程的信息:

(lldb) thread info thread #1: tid = 0xe8ad0, 0x00000001083515a0 MyApp`MyApp.ViewController.sliderMoved (sender=0x00007fd221486340, self=0x00007fd22161c1a0)(ObjectiveC.UISlider) -> () + 112 at ViewController.swift:20, queue = 'com.apple.main-thread', stop reason = breakpoint 2.1

如果 queue 的值为 com.apple.main-thread,那么您在主线程上。


A
Albert Renshaw

以下模式将确保在主线程上执行方法:

- (void)yourMethod {
    // make sure this runs on the main thread 
    if (![NSThread isMainThread]) {
        [self performSelectorOnMainThread:_cmd/*@selector(yourMethod)*/
                               withObject:nil
                            waitUntilDone:YES];
        return;
    }
    // put your code for yourMethod here
}

_cmd 将自动使用将您的代码段粘贴到 ʕ•ᴥ•ʔ 中的方法
P
Peter Lapisu
void ensureOnMainQueue(void (^block)(void)) {

    if ([[NSOperationQueue currentQueue] isEqual:[NSOperationQueue mainQueue]]) {

        block();

    } else {

        [[NSOperationQueue mainQueue] addOperationWithBlock:^{

            block();

        }];

    }

}

请注意,我检查的是操作队列,而不是线程,因为这是一种更安全的方法


这应该是公认的答案,主线程!=主队列
T
Tom Howard

两种方式。从@rano的回答中,

[[NSThread currentThread] isMainThread] ? NSLog(@"MAIN THREAD") : NSLog(@"NOT MAIN THREAD");

还,

[[NSThread mainThread] isEqual:[NSThread currentThread]] ? NSLog(@"MAIN THREAD") : NSLog(@"NOT MAIN THREAD");

D
Daniele D.

对于 Monotouch / Xamarin iOS,您可以通过以下方式执行检查:

if (NSThread.Current.IsMainThread)
{
    DoSomething();
}
else
{
    BeginInvokeOnMainThread(() => DoSomething());
}

V
Vasily Bodnarchuk

细节

斯威夫特 5.1,Xcode 11.3.1

解决方案 1. 检测任何队列

Get current DispatchQueue?

解决方案 2. 仅检测主队列

import Foundation

extension DispatchQueue {

    private struct QueueReference { weak var queue: DispatchQueue? }

    private static let key: DispatchSpecificKey<QueueReference> = {
        let key = DispatchSpecificKey<QueueReference>()
        let queue = DispatchQueue.main
        queue.setSpecific(key: key, value: QueueReference(queue: queue))
        return key
    }()

    static var isRunningOnMainQueue: Bool { getSpecific(key: key)?.queue == .main }
}

用法

if DispatchQueue.isRunningOnMainQueue { ... }

样本

func test(queue: DispatchQueue) {
    queue.async {
        print("--------------------------------------------------------")
        print("queue label: \(queue.label)")
        print("is running on main queue: \(DispatchQueue.isRunningOnMainQueue)")
    }
}

test(queue: DispatchQueue.main)
sleep(1)
test(queue: DispatchQueue.global(qos: .background))
sleep(1)
test(queue: DispatchQueue.global(qos: .unspecified))

结果(日志)

--------------------------------------------------------
queue label: com.apple.root.background-qos
is running on main queue: false
--------------------------------------------------------
queue label: com.apple.root.default-qos
is running on main queue: false
--------------------------------------------------------
queue label: com.apple.main-thread
is running on main queue: true

M
Michael

斯威夫特版本

if (NSThread.isMainThread()) {
    print("Main Thread")
}

C
Community

让 isOnMainQueue = (dispatch_queue_get_label(dispatch_get_main_queue()) == dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL))

https://stackoverflow.com/a/34685535/1530581 检查这个答案


M
Mark Cao
Here is a way to detect what the current queue is
extension DispatchQueue {
    //Label of the current dispatch queue.
    static var currentQueueLabel: String { String(cString: __dispatch_queue_get_label(nil)) }

    /// Whether the current queue is a `NSBackgroundActivityScheduler` task.
    static var isCurrentQueueNSBackgroundActivitySchedulerQueue: Bool { currentQueueLabel.hasPrefix("com.apple.xpc.activity.") }

    /// Whether the current queue is a `Main` task.
    static var isCurrentQueueMainQueue: Bool { currentQueueLabel.hasPrefix("com.apple.main-thread") }
}

C
Cœur

更新:根据@demosten 提到的 queue.h 标头,这似乎不是正确的解决方案

当我需要这个功能时,我想到了第一个想法:

dispatch_get_main_queue() == dispatch_get_current_queue();

并查看了公认的解决方案:

[NSThread isMainThread];

我的解决方案快 2.5 倍。

PS 是的,我检查过,它适用于所有线程


有道理 - 您的方法绕过了 obj-c 运行时消息传递系统的开销。虽然如果您使用这种技术,我会说它有一种不好的代码气味,可能是过早优化。
dispatch_get_current_queue() 从 iOs 6.0 开始被弃用
您可以在定义了 dispatch_get_current_queue() 的 Apple 的 queue.h 标头中阅读此内容:When dispatch_get_current_queue() is called on the main thread, it may or may not return the same value as dispatch_get_main_queue(). Comparing the two is not a valid way to test whether code is executing on the main thread.