Is there any way to check whether or not the current thread is the main thread in Objective-C?
I want to do something like this.
- (void)someMethod
{
if (IS_THIS_MAIN_THREAD?) {
NSLog(@"ok. this is main thread.");
} else {
NSLog(@"don't call this method from other thread!");
}
}
Have a look at the NSThread
API documentation.
There are methods like
- (BOOL)isMainThread
+ (BOOL)isMainThread
and + (NSThread *)mainThread
In Swift3
if Thread.isMainThread {
print("Main Thread")
}
If you want a method to be executed on the main thread, you can:
- (void)someMethod
{
dispatch_block_t block = ^{
// Code for the method goes here
};
if ([NSThread isMainThread])
{
block();
}
else
{
dispatch_async(dispatch_get_main_queue(), block);
}
}
If you want to know whether or not you're on the main thread, you can simply use the debugger. Set a breakpoint at the line you're interested in, and when your program reaches it, call this:
(lldb) thread info
This will display information about the thread you're on:
(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
If the value for queue
is com.apple.main-thread
, then you're on the main thread.
The following pattern will assure a method is executed on the 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
will automatically use the method in which your snippet is pasted into ʕ•ᴥ•ʔ
void ensureOnMainQueue(void (^block)(void)) {
if ([[NSOperationQueue currentQueue] isEqual:[NSOperationQueue mainQueue]]) {
block();
} else {
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
block();
}];
}
}
note that i check the operation queue, not the thread, as this is a more safer approach
Two ways. From @rano's answer,
[[NSThread currentThread] isMainThread] ? NSLog(@"MAIN THREAD") : NSLog(@"NOT MAIN THREAD");
Also,
[[NSThread mainThread] isEqual:[NSThread currentThread]] ? NSLog(@"MAIN THREAD") : NSLog(@"NOT MAIN THREAD");
For Monotouch / Xamarin iOS you can perform the check in this way:
if (NSThread.Current.IsMainThread)
{
DoSomething();
}
else
{
BeginInvokeOnMainThread(() => DoSomething());
}
Details
Swift 5.1, Xcode 11.3.1
Solution 1. Detect any queue
Solution 2. Detect only main queue
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 }
}
Usage
if DispatchQueue.isRunningOnMainQueue { ... }
Sample
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))
Result (log)
--------------------------------------------------------
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
Swift Version
if (NSThread.isMainThread()) {
print("Main Thread")
}
let isOnMainQueue = (dispatch_queue_get_label(dispatch_get_main_queue()) == dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL))
check this answer from 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") }
}
UPDATE: seems that is not correct solution, according to queue.h header as mentioned @demosten
The first thought was brought to me, when I was needed this functionality was the line:
dispatch_get_main_queue() == dispatch_get_current_queue();
And had looked to the accepted solution:
[NSThread isMainThread];
mine solution 2.5 times faster.
PS And yes, I'd checked, it works for all threads
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.
Success story sharing
NSOperationQueue.mainQueue().addOperationWithBlock { //your work here }
dispatch_sync()
instead ofdispatch_async()
in your example.