Überprüfen Sie, ob der aktuelle Thread der Haupt-Thread ist


121

Gibt es eine Möglichkeit zu überprüfen, ob der aktuelle Thread der Haupt-Thread in Objective-C ist oder nicht?

Ich möchte so etwas tun.

  - (void)someMethod
  {
    if (IS_THIS_MAIN_THREAD?) {
      NSLog(@"ok. this is main thread.");
    } else {
      NSLog(@"don't call this method from other thread!");
    }
  }

Was ist falsch daran, eine Methode aus anderen Threads aufzurufen?
David 天宇 Wong

Antworten:



24

Wenn Sie möchten, dass eine Methode im Hauptthread ausgeführt wird, können Sie:

- (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
Antworten auf alte Fragen können von einer Erklärung profitieren, wie sich die neue Antwort von vorhandenen Antworten unterscheidet.
Jason Aller

1
Das ist übertrieben, wenn einige Arbeit muss auf der Haupt - Thread ausgeführt werden, gibt es keine Verwendung bei der Überprüfung , ob Sie auf dem Haupt - Thread oder nicht. Tun Sie es einfachNSOperationQueue.mainQueue().addOperationWithBlock { //your work here }
Eric

3
@ Eric Ich stimme zu, aber was ist, wenn Sie die Methode sofort ausführen möchten, wenn Sie sich bereits im Hauptthread befinden? In Ihrem Vorschlag wird die Methode immer zur späteren Ausführung über die Hauptoperationswarteschlange gesendet.
Boherna

@boherna richtig, das ist etwas, worauf man achten muss.
Eric

@boherna Später Kommentar, aber der Punkt, den Sie in Ihrem Kommentar machen, wäre stärker, wenn Sie dispatch_sync()anstelle von dispatch_async()in Ihrem Beispiel verwenden.
Caleb


13

Wenn Sie wissen möchten, ob Sie sich im Hauptthread befinden oder nicht, können Sie einfach den Debugger verwenden. Setzen Sie einen Haltepunkt an der Zeile, an der Sie interessiert sind, und rufen Sie Folgendes auf, wenn Ihr Programm ihn erreicht:

(lldb) thread info

Daraufhin werden Informationen zu dem Thread angezeigt, in dem Sie sich befinden:

(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

Wenn der Wert für queueist com.apple.main-thread, befinden Sie sich im Haupt-Thread.


6

Das folgende Muster stellt sicher, dass eine Methode im Hauptthread ausgeführt wird:

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

_cmdwird automatisch die Methode verwenden, mit der Ihr Snippet in ʕ • ᴥ • ʔ eingefügt wird
Albert Renshaw

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

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

        block();

    } else {

        [[NSOperationQueue mainQueue] addOperationWithBlock:^{

            block();

        }];

    }

}

Beachten Sie, dass ich die Operationswarteschlange überprüfe, nicht den Thread, da dies ein sicherer Ansatz ist


Dies sollte die akzeptierte Antwort sein, Hauptthread! = Hauptwarteschlange
Eisenbahnparade

2

Zwei Wege. Aus der Antwort von @ rano,

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

Ebenfalls,

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

2

Für Monotouch / Xamarin iOS können Sie die Prüfung folgendermaßen durchführen:

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

1

Schnelle Version


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


0

Einzelheiten

  • Swift 5.1, Xcode 11.3.1

Lösung 1. Erkennen Sie eine Warteschlange

Aktuelle DispatchQueue abrufen?

Lösung 2. Erkennen Sie nur die Hauptwarteschlange

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

Verwendung

if DispatchQueue.isRunningOnMainQueue { ... }

Stichprobe

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))

Ergebnis (Protokoll)

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

UPDATE: scheint die richtige Lösung zu sein, laut queue.h Header wie erwähnt @demosten

Der erste Gedanke wurde mir gebracht, als ich gebraucht wurde, war diese Funktionalität die Linie:

dispatch_get_main_queue() == dispatch_get_current_queue();

Und hatte auf die akzeptierte Lösung geschaut:

[NSThread isMainThread];

Minenlösung 2,5 mal schneller.

PS Und ja, ich hatte überprüft, es funktioniert für alle Threads


3
Sinnvoll - Ihre Methode umgeht den Overhead des obj-c-Laufzeitnachrichtensystems. Wenn Sie diese Technik verwenden, würde ich sagen, dass sie nach schlechtem Code riecht, vielleicht nach vorzeitiger Optimierung.
ArtOfWarfare

4
dispatch_get_current_queue () ist von iOs 6.0
Durai Amuthan.H

33
Sie können dies in der Beschreibung von Apples queue.h-Header lesen, in der dispatch_get_current_queue () definiert ist: 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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.