Kiểm tra xem luồng hiện tại có phải là luồng chính hay không


121

Có cách nào để kiểm tra xem luồng hiện tại có phải là luồng chính trong Objective-C hay không?

Tôi muốn làm một cái gì đó như thế này.

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

có gì sai khi gọi một phương thức từ các chủ đề khác?
David 天宇 Wong

Câu trả lời:



24

Nếu bạn muốn một phương thức được thực thi trên chuỗi chính, bạn có thể:

- (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
Câu trả lời cho các câu hỏi cũ có thể được hưởng lợi từ việc giải thích câu trả lời mới khác với câu trả lời hiện có như thế nào.
Jason Aller

1
Điều này là quá mức cần thiết, nếu một số công việc phải được thực hiện trên luồng chính, sẽ không có tác dụng gì trong việc kiểm tra xem bạn có đang ở trên luồng chính hay không. Just doNSOperationQueue.mainQueue().addOperationWithBlock { //your work here }
Eric

3
@Eric Tôi đồng ý, nhưng nếu bạn muốn thực thi phương thức ngay lập tức nếu đã có trong chuỗi chính? Theo gợi ý của bạn, phương pháp này luôn được gửi đi để được thực thi sau này thông qua hàng đợi thao tác chính.
boherna

@boherna chính xác, đó là điều cần chú ý.
Eric

@boherna Nhận xét muộn, nhưng ý bạn đưa ra trong nhận xét của mình sẽ mạnh hơn nếu bạn sử dụng dispatch_sync()thay vì dispatch_async()trong ví dụ của mình.
Caleb


13

Nếu bạn muốn biết liệu bạn có đang ở trên luồng chính hay không, bạn chỉ cần sử dụng trình gỡ lỗi. Đặt một điểm ngắt ở dòng mà bạn quan tâm và khi chương trình của bạn đạt đến điểm đó, hãy gọi thế này:

(lldb) thread info

Điều này sẽ hiển thị thông tin về chuỗi bạn đang tham gia:

(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

Nếu giá trị cho queuecom.apple.main-thread, thì bạn đang ở trên chuỗi chính.


6

Mẫu sau sẽ đảm bảo một phương thức được thực thi trên luồng chính:

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

_cmdsẽ tự động sử dụng các phương pháp trong đó đoạn mã của bạn được dán vào ʕ • ᴥ • ʔ
Albert Renshaw

3

Hai lối. Từ câu trả lời của @ rano,

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

Cũng thế,

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

        }];

    }

}

lưu ý rằng tôi kiểm tra hàng đợi hoạt động, không phải luồng, vì đây là cách tiếp cận an toàn hơn


Đây phải là câu trả lời được chấp nhận, main thread! = Main queue
railparade

2

Đối với Monotouch / Xamarin iOS, bạn có thể thực hiện kiểm tra theo cách sau:

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

1

Phiên bản Swift


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


0

Chi tiết

  • Swift 5.1, Xcode 11.3.1

Giải pháp 1. Phát hiện bất kỳ hàng đợi nào

Nhận DispatchQueue hiện tại?

Giải pháp 2. Chỉ phát hiện hàng đợi chính

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

Sử dụng

if DispatchQueue.isRunningOnMainQueue { ... }

Mẫu vật

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

Kết quả (nhật ký)

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

CẬP NHẬT: có vẻ như đó không phải là giải pháp chính xác, theo tiêu đề queue.h như đã đề cập @demosten

Ý nghĩ đầu tiên đến với tôi, khi tôi cần chức năng này là dòng:

dispatch_get_main_queue() == dispatch_get_current_queue();

Và đã xem xét giải pháp được chấp nhận:

[NSThread isMainThread];

dung dịch mìn nhanh hơn 2,5 lần.

Tái bút Và vâng, tôi đã kiểm tra, nó hoạt động cho tất cả các chuỗi


3
Có ý nghĩa - phương pháp của bạn bỏ qua chi phí của hệ thống nhắn tin thời gian chạy obj-c. Mặc dù nếu bạn đang sử dụng kỹ thuật này, tôi muốn nói rằng nó có mùi mã xấu, có lẽ là do tối ưu hóa quá sớm.
ArtOfWarfare

4
Dispatch_get_current_queue () không được chấp nhận từ
iOs

33
Bạn có thể đọc trong mô tả của tiêu đề queue.h của Apple nơi dispatch_get_current_queue () được định nghĩa: 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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.