35

当我在模拟器中运行我的应用程序时,我会在控制台中获得此日志。在 iOS 8 中还没有看到这个。我不太确定是什么原因造成的。有没有其他人遇到过同样的问题,如果是这样,它是如何解决的?或者在这方面有人可以提供任何帮助吗?

4

6 回答 6

68

不要从主线程以外的任何地方更改 UI。虽然它似乎可以在某些操作系统或设备上运行,而不是在其他设备上运行,但它必然会使您的应用程序不稳定,并意外崩溃。

如果您必须响应可能在后台发生的通知,确保UIKit调用发生在主线程上

你至少有这两个选择:

异步调度

如果可以在任何线程上通知您的观察者,请使用GCD (Grand Central Dispatch) 。您可以从任何线程收听并执行工作,并将 UI 更改封装在dispatch_async

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

何时使用GCD?当您无法控制谁发送通知时。它可以是操作系统、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];

不保证仅从所述方法调用观察者的混合解决方案。它允许更轻的观察者,但代价是不那么健壮的设计。此处仅提及作为您可能应该避免的解决方案。

于 2015-08-11T21:13:45.037 回答
20

斯威夫特 3.0

DispatchQueue.main.async {
}
于 2016-10-11T13:36:04.243 回答
5

您需要移动到 App 的主线程中的所有 UI 部分更新。

我在后台调用createMenuView()并出现以下错误

“此应用程序正在从后台线程修改自动布局引擎,这可能导致引擎损坏和奇怪的崩溃”

所以我将上述方法调用到主线程中

    DispatchQueue.main.async {
    }

在 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)
            })
        }
    }
于 2016-10-25T16:02:23.987 回答
4

应该尝试符号断点来检测问题:-在此处输入图像描述

象征:

[UIView layoutIfNeeded]

健康)状况:

!(BOOL)[NSThread isMainThread]

然后将您的 UI 更新代码放在主线程中

DispatchQueue.main.async {}
于 2017-07-20T11:10:35.850 回答
3

您有从后台线程更新 UI 布局的代码。更改运行代码的操作队列不需要明确。例如 NSURLSession.shared() 在发出新请求时不使用主队列。为了确保您的代码在主线程上运行,我使用了 NSOperationQueue 的静态方法 mainQueue()。

迅速:

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

对象-C:

[NSOperationQueue mainQueue] addOperationWithBlock:^{
    //Do UI stuff here
}];
于 2016-05-26T07:38:27.407 回答
1

我的情况也发生了同样的问题,我必须按照以下方式更改代码,然后它才能正常工作。在ViewDidLoad,通过使用调用此方法main thread

[self performSelectorOnMainThread:@selector(setUpTableRows) withObject:nil waitUntilDone:YES];
于 2016-10-06T12:04:48.703 回答