web-dev-qa-db-ja.com

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

アプリケーションをシミュレーターで実行しているときに、コンソールでこのログを取得します。 iOS 8でこれを見たことはありません。これは何が原因なのかよくわかりません。他の誰かが同じ問題に遭遇しましたか?その場合、どのように修正されましたか?またはこれに関して誰でも提供できる助けはありますか?

36

メインスレッド以外のUIは変更しないでください。一部のOSまたはデバイスで動作し、他のデバイスでは動作しないように見える場合がありますが、アプリケーションが不安定になり、予期せずクラッシュする可能性があります。

バックグラウンドでcan発生する通知に応答する必要がある場合は、UIKit呼び出しメインスレッド

少なくとも次の2つのオプションがあります。

非同期ディスパッチ

オブザーバーに任意のスレッドで通知できる場合は、GCD(Grand Central Dispatch)を使用します。任意のスレッドからリッスンして作業を行い、UIの変更をdispatch_async

dispatch_async(dispatch_get_main_queue()) {
    // Do UI stuff here
}

GCDを使用する場合通知の送信者を制御しない場合。 OS、Cocoapod、組み込みライブラリなどを使用できます。GCDを使用すると、いつでも起動します。欠点:作業のスケジュールを変更することになります。


メインスレッドで聞く

便利なことに、queueパラメーターを使用して、オブザーバーに通知するスレッドを指定できます。登録するとき通知に使用します。

addObserverForName:@"notification"
    object:nil
    queue:[NSOperationQueue mainQueue]
    usingBlock:^(NSNotification *note){
        // Do UI stuff here
    }

いつメインスレッドを監視するか?登録と登録の両方をしているとき。あなたが通知に応答する時、あなたはすでにあなたがいる必要がある場所にいます。


メインスレッドでの通知の投稿

[self performSelectorOnMainThread:@selector(postNotification:) withObject:notification waitUntilDone:NO];

保証しないオブザーバーが上記のメソッドからのみ呼び出されるというハイブリッドソリューション。これにより、より堅牢な設計で、より軽いオブザーバーが可能になります。ここでは解決策としてのみ言及されていますおそらく避けるべきです

67
SwiftArchitect

Swift 3.0

DispatchQueue.main.async {
}
20

アプリのメインスレッドに移動する必要があるすべてのUIパーツの更新。

createMenuView()をバックグラウンドで呼び出していましたが、エラーが発生しました

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

だから私は上記のメソッドをメインスレッドに呼び出しました

    DispatchQueue.main.async {
    }

in Swift 3.0およびXcode 8.0

以下に書かれた正しいコード:

RequestAPI.post(postString: postString, url: "https://www.someurl.com") { (succeeded: Bool, msg: String, responceData:AnyObject) -> () in

        if(succeeded) {
            print(items: "User logged in. Registration is done.")

            // Move to the UI thread
            DispatchQueue.main.async (execute: { () -> Void in

                //Set User's logged in
                Util.set_IsUserLoggedIn(state: true)
                Util.set_UserData(userData: responceData)
                self.appDelegate.createMenuView()

            })

        }
        else {
            // Move to the UI thread
            DispatchQueue.main.async (execute: { () -> Void in
                let alertcontroller = UIAlertController(title: JJS_MESSAGE, message: msg, preferredStyle: UIAlertControllerStyle.alert)
                alertcontroller.title = "No Internet"
                alertcontroller.message = FAILURE_MESSAGE
                self.present(alertcontroller, animated: true, completion: nil)
            })
        }
    }
5
Anil Gupta

問題を検出するには、シンボリックブレークポイントを試してください:- enter image description here

シンボル:

[UIView layoutIfNeeded]`

調子:

!(BOOL)[NSThread isMainThread]

次に、UI更新コードをメインスレッドに配置します

DispatchQueue.main.async {}
3
Abdul Hameed

バックグラウンドスレッドからUIレイアウトを更新するコードがあります。コードを実行する操作キューを変更することは明示的である必要はありません。たとえば、NSURLSession.shared()は、新しいリクエストを作成するときにメインキューを使用しません。コードをメインスレッドで実行するために、NSOperationQueueの静的メソッドmainQueue()を使用しています。

迅速:

NSOperationQueue.mainQueue().addOperationWithBlock(){
    //Do UI stuff here
}

Obj-C:

[NSOperationQueue mainQueue] addOperationWithBlock:^{
    //Do UI stuff here
}];
3
Nikolay

私の場合も同じ問題が発生します。次の方法でコードを変更する必要があります。 ViewDidLoadで、main threadを使用してこのメ​​ソッドを呼び出し、

[self performSelectorOnMainThread:@selector(setUpTableRows) withObject:nil waitUntilDone:YES];
0
Preetha