Periksa apakah utas saat ini adalah utas utama atau bukan

121

Apakah ada cara untuk memeriksa apakah utas saat ini adalah utas utama di Objective-C atau bukan?

Saya ingin melakukan sesuatu seperti ini.

  - (void)someMethod
  {
    if (IS_THIS_MAIN_THREAD?) {
      NSLog(@"ok. this is main thread.");
    } else {
      NSLog(@"don't call this method from other thread!");
    }
  }
kentang ikan
sumber
apa yang salah tentang memanggil metode dari utas lain?
David 天宇 Wong

Jawaban:

24

Jika Anda ingin sebuah metode dijalankan di utas utama, Anda dapat:

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

    if ([NSThread isMainThread])
    {
        block();
    }
    else
    {
        dispatch_async(dispatch_get_main_queue(), block);
    }
}
boherna
sumber
5
Jawaban atas pertanyaan lama bisa mendapatkan keuntungan dari penjelasan tentang bagaimana jawaban baru berbeda dari jawaban yang sudah ada.
Jason Aller
1
Ini berlebihan, jika beberapa pekerjaan harus dilakukan pada utas utama, tidak ada gunanya memeriksa apakah Anda berada di utas utama atau tidak. Lakukan sajaNSOperationQueue.mainQueue().addOperationWithBlock { //your work here }
Eric
3
@Eric Saya setuju, tetapi bagaimana jika Anda ingin segera mengeksekusi metode jika sudah ada di utas utama? Dalam saran Anda, metode ini selalu dikirim untuk dijalankan nanti melalui antrian operasi utama.
boherna
@ Boherna benar, itu adalah sesuatu yang harus diperhatikan.
Eric
@boherna Komentar terlambat, tetapi poin yang Anda buat dalam komentar Anda akan lebih kuat jika Anda menggunakan, dispatch_sync()bukan dispatch_async()dalam contoh Anda.
Kaleb
22

Di Swift3

if Thread.isMainThread {
    print("Main Thread")
}
dimo hamdy
sumber
13

Jika Anda ingin mengetahui apakah Anda berada di thread utama atau tidak, Anda cukup menggunakan debugger. Tetapkan breakpoint pada garis yang Anda minati, dan ketika program Anda mencapainya, panggil ini:

(lldb) thread info

Ini akan menampilkan informasi tentang utas tempat Anda berada:

(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

Jika nilainya queueadalah com.apple.main-thread, maka Anda berada di utas utama.

Eric
sumber
6

Pola berikut akan memastikan sebuah metode dijalankan di utas utama:

- (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
}
TJ
sumber
_cmdakan secara otomatis menggunakan metode di mana cuplikan Anda ditempelkan ke ʕ • ᴥ • ʔ
Albert Renshaw
3

Dua arah. Dari jawaban @ rano,

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

Juga,

[[NSThread mainThread] isEqual:[NSThread currentThread]] ? NSLog(@"MAIN THREAD") : NSLog(@"NOT MAIN THREAD");
Tom Howard
sumber
3
void ensureOnMainQueue(void (^block)(void)) {

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

        block();

    } else {

        [[NSOperationQueue mainQueue] addOperationWithBlock:^{

            block();

        }];

    }

}

perhatikan bahwa saya memeriksa antrian operasi, bukan utas, karena ini adalah pendekatan yang lebih aman

Peter Lapisu
sumber
Ini harus menjadi jawaban yang diterima, utas utama! = Antrian utama
railarade
2

Untuk Monotouch / Xamarin iOS Anda dapat melakukan pemeriksaan dengan cara ini:

if (NSThread.Current.IsMainThread)
{
    DoSomething();
}
else
{
    BeginInvokeOnMainThread(() => DoSomething());
}
Daniele D.
sumber
1

Versi Swift


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

let isOnMainQueue = (dispatch_queue_get_label (dispatch_get_main_queue ()) == dispatch_queue_get_label (DISPATCH_CURRENT_QUEUE_LABEL))

periksa jawaban ini dari https://stackoverflow.com/a/34685535/1530581

JerryZhou
sumber
0

Detail

  • Swift 5.1, Xcode 11.3.1

Solusi 1. Deteksi antrian apapun

Dapatkan DispatchQueue saat ini?

Solusi 2. Deteksi antrian utama saja

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

Pemakaian

if DispatchQueue.isRunningOnMainQueue { ... }

Sampel

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

Hasil (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
Bodnarchuk dengan mudah
sumber
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") }
}
Mark Cao
sumber
-2

UPDATE: sepertinya itu bukan solusi yang benar, menurut header queue.h seperti yang disebutkan @demosten

Pikiran pertama dibawa ke saya, ketika saya dibutuhkan fungsi ini adalah baris:

dispatch_get_main_queue() == dispatch_get_current_queue();

Dan telah melihat solusi yang diterima:

[NSThread isMainThread];

solusi tambang 2,5 kali lebih cepat.

PS Dan ya, saya sudah memeriksa, itu berfungsi untuk semua utas

HotJard
sumber
3
Masuk akal - metode Anda melewati overhead sistem pesan runtime obj-c. Meskipun jika Anda menggunakan teknik ini, menurut saya ini memiliki bau kode yang buruk, mungkin itu adalah pengoptimalan prematur.
ArtOfWarfare
4
dispatch_get_current_queue () tidak digunakan lagi dari iOs 6.0
Durai Amuthan.H
33
Anda dapat membaca ini dalam deskripsi header queue.h Apple di mana dispatch_get_current_queue () didefinisikan: 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