有什么方法可以检查当前线程是否是 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!");
}
}
有类似的方法
- (BOOL)isMainThread
+ (BOOL)isMainThread
和+ (NSThread *)mainThread
在 Swift3 中
if Thread.isMainThread {
print("Main Thread")
}
如果你想在主线程上执行一个方法,你可以:
- (void)someMethod
{
dispatch_block_t block = ^{
// Code for the method goes here
};
if ([NSThread isMainThread])
{
block();
}
else
{
dispatch_async(dispatch_get_main_queue(), block);
}
}
如果你想知道你是否在主线程上,你可以简单地使用调试器。在您感兴趣的行设置一个断点,当您的程序到达它时,调用它:
(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
,那么您在主线程上。
以下模式将确保在主线程上执行方法:
- (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
将自动使用将您的代码段粘贴到 ʕ•ᴥ•ʔ 中的方法
void ensureOnMainQueue(void (^block)(void)) {
if ([[NSOperationQueue currentQueue] isEqual:[NSOperationQueue mainQueue]]) {
block();
} else {
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
block();
}];
}
}
请注意,我检查的是操作队列,而不是线程,因为这是一种更安全的方法
两种方式。从@rano的回答中,
[[NSThread currentThread] isMainThread] ? NSLog(@"MAIN THREAD") : NSLog(@"NOT MAIN THREAD");
还,
[[NSThread mainThread] isEqual:[NSThread currentThread]] ? NSLog(@"MAIN THREAD") : NSLog(@"NOT MAIN THREAD");
对于 Monotouch / Xamarin iOS,您可以通过以下方式执行检查:
if (NSThread.Current.IsMainThread)
{
DoSomething();
}
else
{
BeginInvokeOnMainThread(() => DoSomething());
}
细节
斯威夫特 5.1,Xcode 11.3.1
解决方案 1. 检测任何队列
解决方案 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
斯威夫特版本
if (NSThread.isMainThread()) {
print("Main Thread")
}
让 isOnMainQueue = (dispatch_queue_get_label(dispatch_get_main_queue()) == dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL))
从 https://stackoverflow.com/a/34685535/1530581 检查这个答案
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") }
}
更新:根据@demosten 提到的 queue.h 标头,这似乎不是正确的解决方案
当我需要这个功能时,我想到了第一个想法:
dispatch_get_main_queue() == dispatch_get_current_queue();
并查看了公认的解决方案:
[NSThread isMainThread];
我的解决方案快 2.5 倍。
PS 是的,我检查过,它适用于所有线程
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.
NSOperationQueue.mainQueue().addOperationWithBlock { //your work here }
dispatch_sync()
而不是dispatch_async()
,您在评论中提出的观点会更加有力。