현재 스레드가 메인 스레드인지 확인


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!");
    }
  }

다른 스레드에서 메서드를 호출하는 것이 잘못된 이유는 무엇입니까?
David 天宇 Wong

답변:


165

NSThreadAPI 문서를 살펴보십시오 .

다음과 같은 방법이 있습니다.

- (BOOL)isMainThread

+ (BOOL)isMainThread

+ (NSThread *)mainThread


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
이전 질문에 대한 답변은 새로운 답변이 기존 답변과 어떻게 다른지에 대한 설명에서 도움이 될 수 있습니다.
Jason Aller

1
이것은 과잉 입니다. 메인 스레드에서 일부 작업을 수행 해야하는 경우 메인 스레드에 있는지 여부를 확인할 필요가 없습니다. 그냥하세요NSOperationQueue.mainQueue().addOperationWithBlock { //your work here }
Eric

3
@Eric 동의하지만 이미 주 스레드에있는 경우 메서드를 즉시 실행하려면 어떻게해야합니까? 귀하의 제안에 따르면 메서드는 항상 기본 작업 대기열을 통해 나중에 실행되도록 디스패치됩니다.
boherna

@boherna 맞습니다.주의해야 할 부분입니다.
에릭

@boherna 늦게 댓글을 달았지만 예제 dispatch_sync()대신 사용하면 댓글에서 포인트가 더 강해질 것 dispatch_async()입니다.
Caleb


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

의 값 queuecom.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();

        }];

    }

}

더 안전한 접근 방식이므로 스레드가 아닌 작업 대기열을 확인합니다.


이것은 받아 들여진 대답이어야합니다, 메인 스레드! = 메인 대기열
railwayparade

2

Monotouch / Xamarin iOS의 경우 다음과 같은 방식으로 검사를 수행 할 수 있습니다.

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



0

세부

  • Swift 5.1, Xcode 11.3.1

해결 방법 1. 대기열 감지

현재 DispatchQueue를 받으시겠습니까?

해결 방법 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

업데이트 : @demosten에서 언급했듯이 queue.h 헤더에 따르면 올바른 해결책이 아닌 것 같습니다 .

이 기능이 필요했을 때 첫 번째 생각은 다음과 같습니다.

dispatch_get_main_queue() == dispatch_get_current_queue();

그리고 수용된 솔루션을 찾았습니다.

[NSThread isMainThread];

광산 솔루션 2.5 배 더 빠릅니다.

PS 그리고 예, 확인했습니다. 모든 스레드에서 작동합니다.


3
의미가 있습니다-귀하의 방법은 obj-c 런타임 메시징 시스템의 오버 헤드를 우회합니다. 이 기술을 사용하는 경우 코드 냄새가 나쁘다고 말하고 싶습니다. 아마도 조기 최적화의 냄새 일 수 있습니다.
ArtOfWarfare

4
dispatch_get_current_queue ()는 iOS 용 6.0에서 사용되지 않습니다
Durai Amuthan.H

33
dispatch_get_current_queue ()가 정의 된 Apple의 queue.h 헤더에 대한 설명에서 이것을 읽을 수 있습니다. 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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.