"이 응용 프로그램이 백그라운드 스레드에서 자동 레이아웃 엔진을 수정하고 있습니다"오류가 발생합니까?


310

swift를 사용하여 OS X 에서이 오류가 많이 발생했습니다.

"이 응용 프로그램은 백그라운드 스레드에서 자동 레이아웃 엔진을 수정하여 엔진 손상 및 이상한 충돌로 이어질 수 있습니다. 이는 이후 릴리스에서 예외가 발생합니다."

NSWindowcontentView 가 있고 창 을보기로 바꾸고 있습니다. 창에서 시도하고 할 때 또는 창에 a 를 추가 하면 오류가 발생 합니다. 자동 크기 조정 기능을 사용 중지하려고 시도했지만 자동 레이아웃을 사용하는 것이 없습니다. 이견있는 사람?NSApp.beginSheetsubview

때때로 그것은 괜찮고 아무 일도 일어나지 UI않습니다.


2
어떤 이유로 아래의 훌륭한 답변이 삭제되었습니다 : github.com/nrbrook/NBUIKitMainThreadGuard
Fattie

적어도 몇 시간을 절약했습니다. 감사합니다 @Fattie
oyalhi

맞아요 @oyalhi. 그것을 조심해서 사용하십시오, 나는 그것을 정말로 즐겼지만 다른 문제도있었습니다-힘든 분야입니다! 그것이 도움이되기를 바랍니다!
Fattie

반 관련 질문

답변:


638

스레드 기능 실행이 완료되는 즉시 UI를 업데이트 할 수 있도록 다른 스레드 안에 배치해야합니다.

현대 스위프트 :

DispatchQueue.main.async {
    // Update UI
}

이전 버전의 Swift, pre Swift 3

dispatch_async(dispatch_get_main_queue(){
    // code here
})

목표 -C :

dispatch_async(dispatch_get_main_queue(), ^{
    // code here
});

3
Objective C에서이 작업을 수행하려면 코드 블록에서 {앞에 ^ (void)를 넣고 세미콜론 뒤에옵니다.
avance

4
아프지 않지만 ^ 대신에 ^ (void)는 필요하지 않습니다. 답의 Objective-C 버전은 괜찮습니다.
Keller

2
그것은 나를 위해 잘 작동합니다. 내 문제는 네트워크 요청을하고 내부 성공 완료 블록은 UI를 업데이트하는 함수를 호출했습니다. UIKit은 스레드로부터 안전하지 않으므로 UI를 업데이트하려면 기본 스레드로 다시 디스패치해야합니다.
Rachel

1
의해 답변을 @Naishta Swift 3 솔루션
Nathaniel

1
스위프트 3 : DispatchQueue.main.async () { code }, @Naishta가 말했듯이
smukamuka

146

'dispatch_async'를 사용하지 않고 print 문으로 디버깅하는 동안 유사한 오류 메시지가 표시 되므로 해당 오류 메시지가 표시되면 사용 시간

스위프트 4

DispatchQueue.main.async { //code }

스위프트 3

DispatchQueue.main.async(){ //code }

이전 스위프트 버전

dispatch_async(dispatch_get_main_queue()){ //code }

5
구문이 잘못되었으므로 다음과 같아야합니다. dispatch_async(dispatch_get_main_queue(), ^{ /* UI related code */ });편집 : 답변을 업데이트하면 구문 형식이 더 잘 작동합니다.
Zoltán

1
또는, 클로저 내에서 다음을 사용하여 백그라운드 스레드에서 메인 스레드로 내려옵니다. self.performSelectorOnMainThread (Selector ( "yourFunction :"), withObject : 'yourArray / yourObject', waitUntilDone : true)
Naishta

1
아니, 구문을 살펴보십시오
Naishta

82

실제 문제가 발생한 후에도 "이 응용 프로그램은 백그라운드 스레드에서 자동 레이아웃 엔진을 수정하는 중"오류가 콘솔에 기록되므로 중단 점을 사용하지 않고 디버깅하는 것이 어려울 수 있습니다.

@markussvensson의 답변을 사용하여 문제를 감지 하고이 심볼릭 브레이크 포인트 (디버그> 브레이크 포인트> 심볼릭 브레이크 포인트 만들기)를 사용하여 문제를 발견했습니다 .

  1. 기호 : [UIView layoutIfNeeded]또는[UIView updateConstraintsIfNeeded]
  2. 질환: !(BOOL)[NSThread isMainThread]

여기에 이미지 설명을 입력하십시오

에뮬레이터에서 앱을 빌드하고 실행하고 오류 메시지가 표시되는 단계를 복제하십시오 (앱이 평소보다 느려집니다). 그런 다음 Xcode는 앱을 중지하고 백그라운드 스레드에서 UI에 액세스하는 코드 줄 (예 : func 호출)을 표시합니다.


3
흠. 나는 그것이 말이되는 것처럼 보이기 때문에 이것을 찬성했습니다. 그러나 실행이 중단되지 않고 여전히 로그에 오류가 발생합니다. 상징적 중단 점을 설정하는 데 사용할 수있는 다른 조건이 있습니까?
Sjakelien 2016 년

제 경우에는 깨집니다. 그러나 스택 추적은 어떤 뷰가 책임이 있는지 암시하지 않습니다. 그리고 표시된 어셈블러 코드를 해석하는 방법을 모르겠습니다movq 0x10880ba(%rip), %rsi ; "_wantsReapplicationOfAutoLayoutWithLayoutDirtyOnEntry:"
Reinhard Männer

디버깅 할 때 앱이 심각하게 느려지지 않습니까?
Itachi

@ 이타치 p. 속도를 높이는 방법을 모른다.
k06a

2
Xcode 9부터는 기본 제공 기능입니다. Scheme 설정의 "Diagnostics"탭에서 "Main Thread Checker"옵션이 활성화되어 있는지 확인하십시오
AndrewPo

24

텍스트 필드 값을 업데이트하거나 백그라운드 스레드 내에 하위 뷰를 추가하려고하면이 문제가 발생할 수 있습니다. 따라서 이런 종류의 코드를 메인 스레드에 넣어야합니다.

기본 대기열을 가져 오려면 dispatch_asynch로 UI 업데이트를 호출하는 메서드를 래핑해야합니다. 예를 들면 다음과 같습니다.

dispatch_async(dispatch_get_main_queue(), { () -> Void in
   self.friendLabel.text = "You are following \(friendCount) accounts"
})

편집-스위프트 3 :

이제 다음 코드에 따라이를 수행 할 수 있습니다.

// Move to a background thread to do some long running work
DispatchQueue.global(qos: .userInitiated).async {
   // Do long running task here
   // Bounce back to the main thread to update the UI
   DispatchQueue.main.async {
      self.friendLabel.text = "You are following \(friendCount) accounts"
   }
}

23

나에게이 오류 메시지는 Admob SDK의 배너에서 비롯된 것입니다.

조건부 중단 점을 설정하여 "WebThread"로 원점을 추적 할 수있었습니다.

백그라운드 스레드에서 UI를 업데이트하는 사람을 찾기위한 조건부 중단 점

그런 다음 배너 생성을 캡슐화하여 문제를 제거 할 수있었습니다.

dispatch_async(dispatch_get_main_queue(), ^{
   _bannerForTableFooter = [[GADBannerView alloc] initWithAdSize:kGADAdSizeSmartBannerPortrait];
   ...
}

메인 코드가 아닌 스레드 에서이 코드가 어떻게 호출되는지 알 수 없으므로 이것이 왜 도움이되었는지 모르겠습니다.

그것이 누군가를 도울 수 있기를 바랍니다.


1
나는 같은 문제가 있었다. 왜 WebThread에서 예외가 발생했는지 혼란 스러웠습니다. 나는 당신과 같은 변화를했고 지금은 효과가 있습니다. 약간 오래된 버전의 admob sdk를 사용하고 있습니다. 최신 버전에서 수정되었는지 궁금합니다. 고마워 나는 그것을 찾을 것이라고 생각하지 않습니다.
Larry

1
최신 버전의 AdMob으로 업데이트하면이 문제가 해결되었습니다.
JH95

이 같은 상징적 중단 점에서 휴식을 얻지 만 코드는 표시되지 않습니다. :(
Victor Engel

20

NSURLConnection 비동기 요청 완료 처리기 내에서 UI 업데이트를 수행 한 블록을 호출 할 때 iOS 9 SDK로 업데이트 한 이후이 문제가 발생했습니다. dispatch_main_queue를 사용하여 블록 호출을 dispatch_async에 넣으면 문제가 해결되었습니다.

iOS 8에서 제대로 작동했습니다.


10

내가 사용하고 있었기 때문에 같은 문제가있었습니다 performSelectorInBackground.


아니요, 백그라운드에서해야 할 일이있었습니다. dispatch_async (dispatch_get_main_queue () 메소드 안에 NSNotificationCenter 호출을했는데 작동했습니다
Bobby

URLSessionDelegate에서 데이터를 가져오고 NSNotification을 호출하여 UIViewController가 알림에 응답했으며 거기에서 DispatchQueue.main.async를 사용하여 데이터가 양호했는지 여부를 사용자에게 표시했습니다. 잘못된! -솔루션이 알림을 기본 대기열에 넣습니다. DispatchQueue.main.async {NotificationCenter.default.post (이름 : NSNotification.Name (rawValue : networkNotificationNames.products.rawValue), 객체 : self, userInfo : [networkNotificationNames.products.rawValue : productList])}
iCyberPaul

7

메인 스레드 외부에서 UI를 변경해서는 안됩니다! UIKit은 스레드 안전하지 않으므로 위의 문제와 그렇게하면 다른 이상한 문제가 발생할 수 있습니다. 앱이 충돌 할 수도 있습니다.

따라서 UIKit 작업을 수행하려면 블록을 정의하고 기본 대기열에서 실행되도록해야합니다.

NSOperationQueue.mainQueue().addOperationWithBlock {

}

Xcode 7.2 및 iOS 9.2에서는 사용할 수 없습니다. 다른 대안이 있습니까?
Jayprakash Dubey

7

분명히 당신은 back ground thread에서 UI 업데이트를하고 있습니다. 캔 트는 코드를 보지 않고 정확히 어디에 있는지 예측합니다.

다음과 같은 상황이 발생할 수 있습니다.

백그라운드 스레드에서 무언가를하고 있고 사용하지 않을 수 있습니다. 동일한 기능을 사용하면이 코드를 쉽게 찾을 수 있습니다.

DispatchQueue.main.async { // do UI update here }

백그라운드 스레드에서 웹 요청 호출을 수행하는 func 호출 및 UI 업데이트를 수행하는 다른 func를 호출하는 완료 핸들러. 이 문제를 해결하려면 웹 요청 호출 후 UI를 업데이트 한 코드를 확인하십시오.

// Do something on background thread
DispatchQueue.global(qos: .userInitiated).async {
   // update UI on main thread
   DispatchQueue.main.async {
                // Updating whole table view
                self.myTableview.reloadData()
            }
}

5

"이 응용 프로그램은 백그라운드 스레드에서 자동 레이아웃 엔진을 수정하는 중"이라는 주요 문제는 실제 문제가 발생한 후 오랜 시간이지나 기록되어 문제를 해결하기가 매우 어렵다는 것입니다.

세 개의 상징적 중단 점을 만들어 문제를 해결했습니다.

디버그> 중단 점> 기호 중단 점 작성 ...

중단 점 1 :

  • 상징: -[UIView setNeedsLayout]

  • 질환: !(BOOL)[NSThread isMainThread]

중단 점 2 :

  • 상징: -[UIView layoutIfNeeded]

  • 질환: !(BOOL)[NSThread isMainThread]

중단 점 3 :

  • 상징: -[UIView updateConstraintsIfNeeded]

  • 질환: !(BOOL)[NSThread isMainThread]

이러한 중단 점을 사용하면 기본이 아닌 스레드에서 UI 메소드를 잘못 호출하는 실제 줄에서 쉽게 중단을 얻을 수 있습니다.


4

UITableView에서 데이터를 다시로드하는 동안이 문제가 발생했습니다. 다음과 같이 단순히 다시로드를 보내면 문제가 해결되었습니다.

    dispatch_async(dispatch_get_main_queue(), { () -> Void in
        self.tableView.reloadData()
    })

이것은 나를위한 것이었다! 메인 큐에 다른 모든 것이 있었지만 길잃은 reloadData ()!
Oprimus

3

나는 같은 문제가 있었다. UIAlerts메인 대기열이 필요한 것으로 나타 났습니다 . 하지만 더 이상 사용되지 않습니다 .
나는를 변경하면 UIAlerts받는 사람 UIAlertController, 나는 더 이상 문제가 없었다 및 사용하지 않은 dispatch_async코드를. 교훈-경고에주의하십시오. 그들은 당신이 그것을 기대하지 않을 때에도 도움이됩니다.


3

@Mark의 올바른 코드 답변이 있지만 결과를 공유하기 만하면됩니다. 문제는 뷰의 변경을 요청하고 즉시 발생한다고 가정한다는 것입니다. 실제로 뷰로드는 사용 가능한 리소스에 따라 다릅니다. 모든 것이 빠르게로드되고 지연이 없으면 아무 것도 눈치 채지 못합니다. 프로세스 스레드 등으로 인해 지연이 발생하는 시나리오에서는 애플리케이션이 아직 준비되지 않았더라도 무언가를 표시해야하는 상황이 발생합니다. 따라서 이러한 요청을 비동기 대기열로 발송하여로드에 따라 실행되도록하는 것이 좋습니다.


2

TouchID를 사용할 때 다른 사람을 돕는다면이 문제가 발생했습니다. 메인 큐의 UI로 무언가를 할 수있는 성공 논리를 포장하십시오.


2

텍스트 필드 / 레이블 값을 설정하거나 백그라운드 스레드 내에 하위 뷰를 추가하는 것만 큼 간단하여 필드의 레이아웃이 변경 될 수 있습니다. 인터페이스와 관련된 모든 작업이 메인 스레드에서만 발생하는지 확인하십시오.

이 링크를 확인하십시오 : https://forums.developer.apple.com/thread/7399


2

동일한 ViewController의 UILabel에서 오류 메시지를 업데이트하려고 할 때 동일한 문제가 발생했습니다 (일반 코딩으로 데이터를 업데이트하려고 할 때 데이터를 업데이트하는 데 시간이 조금 걸립니다). DispatchQueueSwift 3 Xcode 8에서 사용 했으며 작동합니다.


2

이 오류를 추적하려면 이슈에서 메인 스레드 검사기 일시 중지 확인란을 사용하십시오. 메인 큐에 문제가있는 행을 전달하여 대부분의 경우를 쉽게 고칠 수 있습니다.

여기에 이미지 설명을 입력하십시오


1
이것이 정확히 무엇입니까? "메인 스레드 검사기"는 기본적으로 활성화되어 있으며 "Thread Sanitizer"와 "Pause on issues"를 추가로 확인했지만 더 이상 정보를 추가하지 않고 "백그라운드 스레드에서 수정"메시지 만 표시합니다.
Neph

백그라운드 스레드에서 UI가 수정되는 시점에서 앱 실행을 일시 중지합니다.
rockdaswift

이상하게도 내 앱 (Xcode 10.2.1)에서는 그렇게하지 않았습니다. 일시 중지하고 코드 줄을 가리 키기 위해 수동으로 중단 점 ( 여기에 설명 된대로 )을 추가해야했습니다.
Neph

이 옵션 세트를 보려면 어떻게해야합니까?
David Rector

편집 대상의 방식은
rockdaswift

1

나에게 문제는 다음과 같습니다. performSegueWithIdentifier:메인 스레드에서 수행 되는지 확인하십시오 .

dispatch_async (dispatch_get_main_queue(), ^{
  [self performSegueWithIdentifier:@"ViewController" sender:nil];
});

1

스위프트 4,

작업 대기열을 사용하여 일부 메소드를 호출하는 경우

operationQueue.addOperation({
            self.searchFavourites()
        })

그리고 함수 searchFavourites가

func searchFavourites() {
     DispatchQueue.main.async {
                    //Your code
                }
}

호출하면 기본 스레드의 "searchFavourites"메소드 내부의 모든 코드가 UI에서 일부 UI를 업데이트하는 경우 여전히 오류가 발생합니다.

이 애플리케이션은 엔진이 메인 스레드에서 액세스 된 후 백그라운드 스레드에서 자동 레이아웃 엔진을 수정합니다.

따라서 솔루션을 사용하십시오.

operationQueue.addOperation({
            DispatchQueue.main.async {
                self.searchFavourites()
            }
        })

이런 종류의 시나리오를 위해.


1

로그에서이 줄을 확인하십시오.

$S12AppName18ViewControllerC11Func()ySS_S2StF + 4420

백그라운드 스레드에서 호출하는 함수 또는 api 메소드를 호출하는 위치가 이와 같이 기본 스레드에서 함수를 호출 해야하는지 확인할 수 있습니다.

DispatchQueue.main.async { func()}

func ()는 API 호출 성공 또는 기타 결과로 호출하려는 함수입니다.

여기에 로그

This application is modifying the autolayout engine from a background thread after the engine was accessed from the main thread. This can lead to engine corruption and weird crashes.
 Stack:(
    0   Foundation                          0x00000001c570ce50 <redacted> + 96
    1   Foundation                          0x00000001c5501868 <redacted> + 32
    2   Foundation                          0x00000001c5544370 <redacted> + 540
    3   Foundation                          0x00000001c5543840 <redacted> + 396
    4   Foundation                          0x00000001c554358c <redacted> + 272
    5   Foundation                          0x00000001c5542e10 <redacted> + 264
    6   UIKitCore                           0x00000001f20d62e4 <redacted> + 488
    7   UIKitCore                           0x00000001f20d67b0 <redacted> + 36
    8   UIKitCore                           0x00000001f20d6eb0 <redacted> + 84
    9   Foundation                          0x00000001c571d124 <redacted> + 76
    10  Foundation                          0x00000001c54ff30c <redacted> + 108
    11  Foundation                          0x00000001c54fe304 <redacted> + 328
    12  UIKitCore                           0x00000001f151dc0c <redacted> + 156
    13  UIKitCore                           0x00000001f151e0c0 <redacted> + 152
    14  UIKitCore                           0x00000001f1514834 <redacted> + 868
    15  UIKitCore                           0x00000001f1518760 <redacted> + 104
    16  UIKitCore                           0x00000001f1543370 <redacted> + 1772
    17  UIKitCore                           0x00000001f1546598 <redacted> + 120
    18  UIKitCore                           0x00000001f14fc850 <redacted> + 1452
    19  UIKitCore                           0x00000001f168f318 <redacted> + 196
    20  UIKitCore                           0x00000001f168d330 <redacted> + 144
    21  AppName                        0x0000000100b8ed00 $S12AppName18ViewControllerC11Func()ySS_S2StF + 4420
    22  AppName                        0x0000000100b8d9f4 $S12CcfU0_y10Foundation4DataVSg_So13NSURLResponseCSgs5Error_pSgtcfU_ + 2384
    23  App NAme                        0x0000000100a98f3c $S10Foundation4DataVSgSo13NSURLResponseCSgs5Error_pSgIegggg_So6NSDataCSgAGSo7NSErrorCSgIeyByyy_TR + 316
    24  CFNetwork                           0x00000001c513aa00 <redacted> + 32
    25  CFNetwork                           0x00000001c514f1a0 <redacted> + 176
    26  Foundation                          0x00000001c55ed8bc <redacted> + 16
    27  Foundation                          0x00000001c54f5ab8 <redacted> + 72
    28  Foundation                          0x00000001c54f4f8c <redacted> + 740
    29  Foundation                          0x00000001c55ef790 <redacted> + 272
    30  libdispatch.dylib                   0x000000010286f824 _dispatch_call_block_and_release + 24
    31  libdispatch.dylib                   0x0000000102870dc8 _dispatch_client_callout + 16
    32  libdispatch.dylib                   0x00000001028741c4 _dispatch_continuation_pop + 528
    33  libdispatch.dylib                   0x0000000102873604 _dispatch_async_redirect_invoke + 632
    34  libdispatch.dylib                   0x00000001028821dc _dispatch_root_queue_drain + 376
    35  libdispatch.dylib                   0x0000000102882bc8 _dispatch_worker_thread2 + 156
    36  libsystem_pthread.dylib             0x00000001c477917c _pthread_wqthread + 472
    37  libsystem_pthread.dylib             0x00000001c477bcec start_wqthread + 4
)

0

또한 창을 초기 값보다 작은 크기로 조정할 때 출력에 이러한 메시지와 스택 추적이 인쇄되는 것을 보면서이 문제가 발생했습니다. 문제를 파악하는 데 오랜 시간을 소비하면서 다소 간단한 해결책을 공유한다고 생각했습니다. IB를 통해 한 번 활성화 Can Draw Concurrently했습니다 NSTextView. 이는 AppKit에게 draw(_:)다른 스레드에서 뷰의 메소드를 호출 할 수 있음을 알려줍니다 . 사용 중지하면 더 이상 오류 메시지가 표시되지 않습니다. macOS 10.14 Beta로 업데이트하기 전에 문제가 발생하지 않았지만 동시에 텍스트보기 작업을 수행하도록 코드를 수정하기 시작했습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.