Compruebe si el hilo actual es el hilo principal o no


121

¿Hay alguna forma de verificar si el hilo actual es o no el hilo principal en Objective-C?

Quiero hacer algo como esto.

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

¿Qué tiene de malo llamar a un método desde otros hilos?
David 天宇 Wong

Respuestas:



24

Si desea que se ejecute un método en el hilo principal, puede:

- (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
Las respuestas a preguntas antiguas pueden beneficiarse de una explicación de cómo la nueva respuesta difiere de las respuestas existentes.
Jason Aller

1
Esto es una exageración, si se debe hacer algo de trabajo en el hilo principal, no sirve de nada comprobar si estás en el hilo principal o no. Solo hazloNSOperationQueue.mainQueue().addOperationWithBlock { //your work here }
Eric

3
@Eric Estoy de acuerdo, pero ¿qué pasa si desea la ejecución inmediata del método si ya está en el hilo principal? En su sugerencia, el método siempre se envía para ejecutarse más tarde a través de la cola de operaciones principal.
boherna

@boherna correcto, eso es algo a tener en cuenta.
Eric

@boherna Comentario tardío, pero el punto que hace en su comentario sería más fuerte si lo usa en dispatch_sync()lugar de dispatch_async()en su ejemplo.
Caleb


13

Si desea saber si está o no en el hilo principal, simplemente puede usar el depurador. Establezca un punto de interrupción en la línea que le interesa y cuando su programa lo alcance, llame a esto:

(lldb) thread info

Esto mostrará información sobre el hilo en el que estás:

(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

Si el valor de queuees com.apple.main-thread, entonces estás en el hilo principal.


6

El siguiente patrón asegurará que un método se ejecute en el hilo principal:

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

_cmdutilizará automáticamente el método en el que se pega el fragmento en ʕ • ᴥ • ʔ
Albert Renshaw

3

Dos caminos. De la respuesta de @ rano,

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

También,

[[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();

        }];

    }

}

tenga en cuenta que verifico la cola de operaciones, no el hilo, ya que este es un enfoque más seguro


Esta debería ser la respuesta aceptada, hilo principal! = Cola principal
desfile ferroviario

2

Para Monotouch / Xamarin iOS, puede realizar la verificación de esta manera:

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

1

Versión rápida


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


0

Detalles

  • Swift 5.1, Xcode 11.3.1

Solución 1. Detecta cualquier cola

¿Obtener DispatchQueue actual?

Solución 2. Detecta solo la cola principal

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

Uso

if DispatchQueue.isRunningOnMainQueue { ... }

Muestra

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

Resultado (registro)

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

ACTUALIZACIÓN: parece que no es la solución correcta, de acuerdo con el encabezado queue.h como se menciona @demosten

El primer pensamiento que se me ocurrió, cuando se necesitaba esta funcionalidad fue la línea:

dispatch_get_main_queue() == dispatch_get_current_queue();

Y había buscado la solución aceptada:

[NSThread isMainThread];

mina solución 2,5 veces más rápida.

PD Y sí, lo había comprobado, funciona para todos los hilos.


3
Tiene sentido: su método evita la sobrecarga del sistema de mensajería en tiempo de ejecución obj-c. Aunque si está utilizando esta técnica, diría que tiene un mal olor a código, quizás a optimización prematura.
ArtOfWarfare

4
dispatch_get_current_queue () está en desuso de iOs 6.0
Durai Amuthan.H

33
Puede leer esto en la descripción del encabezado queue.h de Apple donde se define 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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.