私のOS XでSwiftを使ってこのエラーに遭遇したことがあります。
「このアプリケーションはバックアウトスレッドから自動レイアウトエンジンを変更しているため、エンジンの破損や奇妙なクラッシュにつながる可能性があります。今後のリリースでは例外が発生します。」
私は NSWindow を持っていて、ウィンドウのcontentView
にビューを入れ替えています。ウィンドウでNSApp.beginSheet
を実行しようとしたとき、またはウィンドウにsubview
を追加したときに error が表示されます。自動サイズ変更機能を無効にしようとしましたが、自動レイアウトを使用しているものはありません。何かご意見は?
時にはそれは結構ですし、何も起こらない、他の時はそれは私のUI
を完全に壊し、何もロードしません
わかりました - 答えを見つけました。スレッド関数の実行が完了するとすぐにUIを更新できるようにするために、別のスレッド内に配置する必要があります。
DispatchQueue.main.async {
// Update UI
}
dispatch_async(dispatch_get_main_queue(){
// code here
})
dispatch_async(dispatch_get_main_queue(), ^{
// code here
});
printステートメントでデバッグしているとき 'dispatch_async'を使用していないときと同じようなエラーメッセージが表示される
スイフト4
DispatchQueue.main.async { //code }
スイフト3
DispatchQueue.main.async(){ //code }
以前のSwiftバージョン
dispatch_async(dispatch_get_main_queue()){ //code }
テキストフィールドの値を更新したり、バックグラウンドスレッド内にサブビューを追加しようとすると、この問題が発生します。そのため、この種のコードをメインスレッドに入れる必要があります。
メインキューを取得するには、dispatch_asynchでUIの更新を呼び出すメソッドをラップする必要があります。例えば:
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.friendLabel.text = "You are following \(friendCount) accounts"
})
これで、次のコードに従って実行できます。
// 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"
}
}
私にとっては、このエラーメッセージはAdmob SDKのバナーから発生しました。
条件付きブレークポイントを設定することによって、Originを "WebThread"まで追跡することができました。
それから私はバナー作成を以下でカプセル化することによって問題を取り除くことができました:
dispatch_async(dispatch_get_main_queue(), ^{
_bannerForTableFooter = [[GADBannerView alloc] initWithAdSize:kGADAdSizeSmartBannerPortrait];
...
}
このコードが非メインスレッドからどのように呼び出されたかがわからないため、なぜこれが役立つのかわかりません。
それが誰にでも役立つことを願っています。
NSURLConnection非同期要求完了ハンドラ内でUIを更新するブロックを呼び出していたときにiOS 9 SDKに更新してからこの問題が発生しました。 dispatch_main_queueを使用してブロック呼び出しをdispatch_asyncに配置することで問題は解決しました。
IOS 8ではうまくいった。
私はperformSelectorInBackground
を使っていたので同じ問題を抱えていました。
メインスレッドの外側で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()
}
}
UITableViewでデータをリロードしている間、私はこの問題を抱えていました。次のようにリロードを単にディスパッチするだけで問題は解決しました。
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.tableView.reloadData()
})
私は同じ問題を抱えていました。メインキューが必要なUIAlerts
を使っていたことがわかりました。しかし、それらは 非推奨 です。UIAlerts
をUIAlertController
に変更したとき、私はもう問題を抱えておらず、dispatch_async
コードを使用する必要はありませんでした。レッスン - 警告に注意を払います。あなたがそれを期待していなくても、彼らは助けます。
あなたは@Markからの正しいコードの答えをすでに持っています、ただ私の発見を共有するために:問題はあなたがビューの変更を要求していてそれが即座に起こると仮定しているということです。実際には、ビューのロードは利用可能なリソースによって異なります。すべてが十分に速くロードされ、遅延がない場合は、何も気付きません。プロセススレッドがビジーであるなどの理由で遅延があるシナリオでは、アプリケーションはまだ準備ができていなくても何かを表示するはずの状況に陥ります。したがって、これらの要求を非同期キューに振り分けることをお勧めします。そうすれば、それらの要求は負荷に基づいて実行されます。
同じViewControllerでUILabelのエラーメッセージを更新しようとしたときにも同じ問題が発生しました(通常のコーディングでデータを更新しようとすると、データの更新に少し時間がかかります)。私はSwift 3 Xcode 8でDispatchQueue
を使っていましたが、うまくいきました。
私がTouchIDを使っていたときに私がこの問題を抱えていたのなら、それが他の誰かに役立つなら、あなたの成功ロジックをラップし、それがメインキューのUIで何かをする可能性があります。
テキストフィールド/ラベルの値を設定したり、バックグラウンドスレッド内にサブビューを追加するのと同じくらい簡単なことがあります。これにより、フィールドのレイアウトが変更される可能性があります。あなたがインターフェースですることがメインスレッドでのみ起こることを確認してください。
このリンクをチェックしてください: https://forums.developer.Apple.com/thread/7399
「このアプリケーションは自動レイアウトエンジンをバックグラウンドスレッドから変更しています」の主な問題は、実際の問題が発生してから長い時間ログが記録されているように見えることです。
3つのシンボリックブレークポイントを作成することで、問題を解決できました。
デバッグ>ブレークポイント>シンボリックブレークポイントの作成...
ブレークポイント1:
シンボル:-[UIView setNeedsLayout]
条件:!(BOOL)[NSThread isMainThread]
ブレークポイント2:
シンボル:-[UIView layoutIfNeeded]
条件:!(BOOL)[NSThread isMainThread]
ブレークポイント3:
シンボル:-[UIView updateConstraintsIfNeeded]
条件:!(BOOL)[NSThread isMainThread]
これらのブレークポイントを使用すると、非メインスレッドでUIメソッドを誤って呼び出す実際の行で簡単にブレークを取得できます。
スイフト4、
操作キューを使用して何らかのメソッドを呼び出しているとします。
operationQueue.addOperation({
self.searchFavourites()
})
関数searchFavouritesが次のようになっているとします。
func searchFavourites() {
DispatchQueue.main.async {
//Your code
}
}
メインスレッドの "searchFavourites"メソッド内のすべてのコードを呼び出すと、UIを更新している場合でもエラーが発生します。
エンジンがメインスレッドからアクセスされた後、このアプリケーションはバックグラウンドスレッドからオートレイアウトエンジンを変更しています。
だから解決策を使用して、
operationQueue.addOperation({
DispatchQueue.main.async {
self.searchFavourites()
}
})
このようなシナリオのために。
私にとって問題は以下の通りです。 performSegueWithIdentifier:
がメインスレッドで実行されていることを確認してください。
dispatch_async (dispatch_get_main_queue(), ^{
[self performSegueWithIdentifier:@"ViewController" sender:nil];
});
また、ウィンドウのサイズを初期値よりも小さいサイズに変更したときに、大量のこれらのメッセージとスタックトレースが出力に表示されているのを見ました。問題の解決に長い時間をかけて、私はどちらかといえば簡単な解決策を共有したいと思いました。私はかつてIBを通してNSTextView
でCan Draw Concurrently
を有効にしていました。これはAppKitに、ビューのdraw(_:)
メソッドを別のスレッドから呼び出せることを伝えます。無効にした後、エラーメッセージが表示されなくなりました。私はmacOS 10.14 Betaにアップデートする前に何の問題も経験しませんでしたが、同時に、私はテキストビューで作業を行うためにコードを修正し始めました。