Перевірте, чи поточна нитка є основною


121

Чи є спосіб перевірити, чи є поточний потік головним потоком в 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!");
    }
  }

що не так у виклику методу з інших потоків?
Девід 天宇 Вонг

Відповіді:



24

Якщо ви хочете, щоб метод виконувався в основній нитці, ви можете:

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

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

5
Відповіді на старі питання можуть отримати користь від пояснення того, чим нова відповідь відрізняється від існуючих відповідей.
Джейсон Аллер

1
Це надмірно, якщо потрібно виконати певну роботу над основною ниткою, немає ніякої користі перевіряти, чи є ви на головній нитці чи ні. Просто зробітьNSOperationQueue.mainQueue().addOperationWithBlock { //your work here }
Ерік

3
@Eric Я згоден, але що робити, якщо ви хочете негайного виконання методу, якщо він вже є в основному потоці? За вашою пропозицією, метод завжди відправляється для виконання пізніше через основну чергу операцій.
boherna

@boherna правильна, на це варто дивитися.
Ерік

@boherna Пізній коментар, але пункт, який ви робите у своєму коментарі, був би сильнішим, якщо ви використовуєте dispatch_sync()замість dispatch_async()свого прикладу.
Калеб


13

Якщо ви хочете знати, чи ви не в основному потоці, можете просто скористатися налагоджувачем. Встановіть точку перерви на лінії, яка вас цікавить, і коли ваша програма досягне її, зателефонуйте до цього:

(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, значить, ви перебуваєте в основному потоці.


6

Наступний зразок забезпечить виконання методу на основній нитці:

- (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автоматично використовуватиме метод, у який ваш фрагмент вставлений ʕ • ᴥ • ʔ
Альберт

3

Два способи. З відповіді @ rano,

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

Також,

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

3
void ensureOnMainQueue(void (^block)(void)) {

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

        block();

    } else {

        [[NSOperationQueue mainQueue] addOperationWithBlock:^{

            block();

        }];

    }

}

зауважте, що я перевіряю чергу операцій, а не потік, оскільки це більш безпечний підхід


Це має бути прийнята відповідь, головна тема! = Головна черга
залізничний парад

2

Для iOS Monotouch / Xamarin ви можете перевірити таким чином:

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



0

Деталі

  • Швидкий 5.1, Xcode 11.3.1

Рішення 1. Визначте будь-яку чергу

Отримати поточну чергу DispatchQue?

Рішення 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

0
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") }
}

-2

ОНОВЛЕННЯ: здається, що це неправильне рішення, згідно з заголовком queue.h, як згадується @demosten

Перша думка була мені підказана, коли мені була потрібна ця функціональність:

dispatch_get_main_queue() == dispatch_get_current_queue();

І придивився до прийнятого рішення:

[NSThread isMainThread];

шахтний розчин у 2,5 рази швидший.

PS І так, я перевірив, він працює для всіх потоків


3
Має сенс - ваш метод обходить накладні витрати системи обміну повідомленнями обміну-c. Хоча, якщо ви використовуєте цю техніку, я б сказав, що у неї поганий запах коду, можливо, передчасна оптимізація.
ArtOfWarfare

4
dispatch_get_current_queue () застаріло з iOs 6.0
Durai Amuthan.H

33
Ви можете прочитати це в описі заголовка Apple queue.h, де визначено dispatch_get_current_queue (): 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.
demosten
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.