web-dev-qa-db-ja.com

「このアプリケーションはバックグラウンドスレッドから自動レイアウトエンジンを変更しています」というエラーが表示されますか。

私のOS XでSwiftを使ってこのエラーに遭遇したことがあります。

「このアプリケーションはバックアウトスレッドから自動レイアウトエンジンを変更しているため、エンジンの破損や奇妙なクラッシュにつながる可能性があります。今後のリリースでは例外が発生します。」

私は NSWindow を持っていて、ウィンドウのcontentViewにビューを入れ替えています。ウィンドウでNSApp.beginSheetを実行しようとしたとき、またはウィンドウにsubviewを追加したときに error が表示されます。自動サイズ変更機能を無効にしようとしましたが、自動レイアウトを使用しているものはありません。何かご意見は?

時にはそれは結構ですし、何も起こらない、他の時はそれは私のUIを完全に壊し、何もロードしません

280
Mark

わかりました - 答えを見つけました。スレッド関数の実行が完了するとすぐにUIを更新できるようにするために、別のスレッド内に配置する必要があります。

スイフト3

 DispatchQueue.main.async {
    // Update UI
 }

スイフトバージョン<3

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

Objective-Cのバージョン

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

printステートメントでデバッグしているとき 'dispatch_async'を使用していないときと同じようなエラーメッセージが表示される

スイフト4

DispatchQueue.main.async { //code }

スイフト3

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

以前のSwiftバージョン

dispatch_async(dispatch_get_main_queue()){ //code }
142
Naishta

私の問題を検出するために@markussvenssonの回答を使用し、これを使用してそれを見つけました Symbolic Breakpoint

  1. 記号:[UIView layoutIfNeeded]または[UIView updateConstraintsIfNeeded]
  2. 条件:!(BOOL)[NSThread isMainThread]

enter image description here

69
k06a

テキストフィールドの値を更新したり、バックグラウンドスレッド内にサブビューを追加しようとすると、この問題が発生します。そのため、この種のコードをメインスレッドに入れる必要があります。

メインキューを取得するには、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"
   }
}
25

私にとっては、このエラーメッセージはAdmob SDKのバナーから発生しました。

条件付きブレークポイントを設定することによって、Originを "WebThread"まで追跡することができました。

conditional breakpoint to find who is updating ui from background thread

それから私はバナー作成を以下でカプセル化することによって問題を取り除くことができました:

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

このコードが非メインスレッドからどのように呼び出されたかがわからないため、なぜこれが役立つのかわかりません。

それが誰にでも役立つことを願っています。

21
markussvensson

NSURLConnection非同期要求完了ハンドラ内でUIを更新するブロックを呼び出していたときにiOS 9 SDKに更新してからこの問題が発生しました。 dispatch_main_queueを使用してブロック呼び出しをdispatch_asyncに配置することで問題は解決しました。

IOS 8ではうまくいった。

19
spongessuck

私はperformSelectorInBackgroundを使っていたので同じ問題を抱えていました。

10
Bobby

メインスレッドの外側でUIを変更してはいけません。 UIKitはスレッドセーフではないので、あなたがそれをすると上記の問題や他のいくつかの奇妙な問題が起こるでしょう。アプリがクラッシュする可能性もあります。

そのため、UIKit操作を行うには、ブロックを定義し、それをメインキューで実行させる必要があります。

NSOperationQueue.mainQueue().addOperationWithBlock {

}

明らかにあなたはバックグラウンドスレッドで何らかのUI更新をしています。コードを見なくても、正確な場所を正確に予測できます。

これらはそれが起こるかもしれないいくつかの状況です: -

バックグラウンドスレッドで何かをしていて、使用していない可能性があります。同じコードであるため、このコードは簡単に見つけられます。

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

バックグラウンドスレッドでWeb要求を呼び出す関数を呼び出すことと、UI更新を行う他の関数を呼び出す完了ハンドラこれを解決するには、webrequest呼び出しの後に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()
            }
}
6
Ashish Pisey

UITableViewでデータをリロードしている間、私はこの問題を抱えていました。次のようにリロードを単にディスパッチするだけで問題は解決しました。

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

私は同じ問題を抱えていました。メインキューが必要なUIAlertsを使っていたことがわかりました。しかし、それらは 非推奨 です。
UIAlertsUIAlertControllerに変更したとき、私はもう問題を抱えておらず、dispatch_asyncコードを使用する必要はありませんでした。レッスン - 警告に注意を払います。あなたがそれを期待していなくても、彼らは助けます。

3
epaus

あなたは@Markからの正しいコードの答えをすでに持っています、ただ私の発見を共有するために:問題はあなたがビューの変更を要求していてそれが即座に起こると仮定しているということです。実際には、ビューのロードは利用可能なリソースによって異なります。すべてが十分に速くロードされ、遅延がない場合は、何も気付きません。プロセススレッドがビジーであるなどの理由で遅延があるシナリオでは、アプリケーションはまだ準備ができていなくても何かを表示するはずの状況に陥ります。したがって、これらの要求を非同期キューに振り分けることをお勧めします。そうすれば、それらの要求は負荷に基づいて実行されます。

3
Mukund Agarwal

同じViewControllerでUILabelのエラーメッセージを更新しようとしたときにも同じ問題が発生しました(通常のコーディングでデータを更新しようとすると、データの更新に少し時間がかかります)。私はSwift 3 Xcode 8でDispatchQueueを使っていましたが、うまくいきました。

2
FN90

私がTouchIDを使っていたときに私がこの問題を抱えていたのなら、それが他の誰かに役立つなら、あなたの成功ロジックをラップし、それがメインキューのUIで何かをする可能性があります。

2
Stuart P.

テキストフィールド/ラベルの値を設定したり、バックグラウンドスレッド内にサブビューを追加するのと同じくらい簡単なことがあります。これにより、フィールドのレイアウトが変更される可能性があります。あなたがインターフェースですることがメインスレッドでのみ起こることを確認してください。

このリンクをチェックしてください: https://forums.developer.Apple.com/thread/7399

2
Kiran P Nair

「このアプリケーションは自動レイアウトエンジンをバックグラウンドスレッドから変更しています」の主な問題は、実際の問題が発生してから長い時間ログが記録されているように見えることです。

3つのシンボリックブレークポイントを作成することで、問題を解決できました。

デバッグ>ブレークポイント>シンボリックブレークポイントの作成...

ブレークポイント1:

  • シンボル:-[UIView setNeedsLayout]

  • 条件:!(BOOL)[NSThread isMainThread]

ブレークポイント2:

  • シンボル:-[UIView layoutIfNeeded]

  • 条件:!(BOOL)[NSThread isMainThread]

ブレークポイント3:

  • シンボル:-[UIView updateConstraintsIfNeeded]

  • 条件:!(BOOL)[NSThread isMainThread]

これらのブレークポイントを使用すると、非メインスレッドでUIメソッドを誤って呼び出す実際の行で簡単にブレークを取得できます。

1

スイフト4、

操作キューを使用して何らかのメソッドを呼び出しているとします。

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

関数searchFavouritesが次のようになっているとします。

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

メインスレッドの "searchFavourites"メソッド内のすべてのコードを呼び出すと、UIを更新している場合でもエラーが発生します。

エンジンがメインスレッドからアクセスされた後、このアプリケーションはバックグラウンドスレッドからオートレイアウトエンジンを変更しています。

だから解決策を使用して、

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

このようなシナリオのために。

1
Pramod More

このエラーを捜したい場合は、メインスレッドチェッカーの課題で一時停止チェックボックスを使用してください。ほとんどの場合、それを修正するのは簡単で、問題のある行をメインキューに入れます。

enter image description here

1
rockdaswift

私にとって問題は以下の通りです。 performSegueWithIdentifier:がメインスレッドで実行されていることを確認してください。

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

また、ウィンドウのサイズを初期値よりも小さいサイズに変更したときに、大量のこれらのメッセージとスタックトレースが出力に表示されているのを見ました。問題の解決に長い時間をかけて、私はどちらかといえば簡単な解決策を共有したいと思いました。私はかつてIBを通してNSTextViewCan Draw Concurrentlyを有効にしていました。これはAppKitに、ビューのdraw(_:)メソッドを別のスレッドから呼び出せることを伝えます。無効にした後、エラーメッセージが表示されなくなりました。私はmacOS 10.14 Betaにアップデートする前に何の問題も経験しませんでしたが、同時に、私はテキストビューで作業を行うためにコードを修正し始めました。

0
Andreas