出现 "This application is modifying the autolayout engine from a background thread" 错误?
Getting a "This application is modifying the autolayout engine from a background thread" error?
在我的 OS X using swift 中经常遇到这个错误:
"This application is modifying the autolayout engine from a background thread, which can lead to engine corruption and weird crashes. This will cause an exception in a future release."
我有一个 NSWindow,我正在将视图交换到 window 的 contentView
。当我尝试在 window 上执行 NSApp.beginSheet
或向 window 添加 subview
时,我得到 error .尝试禁用自动调整大小的东西,但我没有使用自动布局的任何东西。有什么想法吗?
有时它很好但什么也没有发生,其他时候它完全破坏了我的 UI
并且没有任何加载
它需要放在不同的线程中,允许 UI 在线程函数执行完成后立即更新:
现代Swift:
DispatchQueue.main.async {
// Update UI
}
旧版本 Swift,pre Swift 3.
dispatch_async(dispatch_get_main_queue(){
// code here
})
Objective-C:
dispatch_async(dispatch_get_main_queue(), ^{
// code here
});
遇到了同样的问题,因为我使用的是 performSelectorInBackground
。
自从更新到 iOS 9 SDK 后,我遇到了这个问题,当时我正在调用一个在 NSURLConnection 异步请求完成处理程序中执行 UI 更新的块。使用 dispatch_main_queue 将块调用放入 dispatch_async 解决了这个问题。
它在 iOS 8.
中运行良好
我在使用 TouchID 时遇到了这个问题,如果这对其他人有帮助,请包装您的成功逻辑,这可能会对主队列中的 UI 执行某些操作。
在不使用 'dispatch_async' 的情况下 使用打印语句 进行调试时,您会收到类似的错误消息
因此,当您收到该错误消息时,是时候使用
Swift 4
DispatchQueue.main.async { //code }
Swift 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"
})
已编辑 - SWIFT 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"
}
}
我遇到了同样的问题。原来我使用的是 UIAlerts
需要主队列。但是,它们已被 弃用 。
当我将 UIAlerts
更改为 UIAlertController
时,我不再有问题并且不必使用任何 dispatch_async
代码。教训——注意警告。即使在您意想不到的时候,它们也会提供帮助。
你一定不能改UI越位主线程! UIKit不是线程安全的,所以如果你这样做会出现上述问题以及其他一些奇怪的问题。该应用程序甚至会崩溃。
所以,要进行UIKit操作,需要定义block,让它在主队列上执行:如,
NSOperationQueue.mainQueue().addOperationWithBlock {
}
它可以像设置文本字段/标签值或在后台线程中添加子视图一样简单,这可能会导致字段布局发生变化。确保您对界面所做的任何操作仅发生在主线程中。
对我而言,此错误消息源自 Admob SDK 的横幅。
通过设置条件断点,我能够将原点追踪到 "WebThread"。
然后我可以通过封装横幅创建来解决这个问题:
dispatch_async(dispatch_get_main_queue(), ^{
_bannerForTableFooter = [[GADBannerView alloc] initWithAdSize:kGADAdSizeSmartBannerPortrait];
...
}
我不知道为什么这有帮助,因为我看不到这段代码是如何从非主线程调用的。
希望对大家有所帮助。
您已经从@Mark 那里获得了正确的代码答案,但是,只是为了分享我的发现:
问题是您请求更改视图并假设它会立即发生。实际上,视图的加载取决于可用资源。如果一切都加载得足够快并且没有延迟,那么您就不会注意到任何事情。在某些情况下,由于进程线程繁忙等原因导致任何延迟,应用程序会遇到一种情况,即它应该显示某些内容,即使它尚未准备好。因此,建议在异步队列中分派这些请求,以便它们根据负载执行。
我在 UITableView 中重新加载数据时遇到了这个问题。只需按如下方式调度重新加载即可解决我的问题。
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.tableView.reloadData()
})
"this application is modifying the autolayout engine from a background thread" 错误在实际问题发生很久之后才记录在控制台中,因此如果不使用断点,调试起来会很困难。
我使用@markussvensson 的回答来检测我的问题并使用这个符号断点(调试 > 断点 > 创建符号断点)找到它:
- 符号:
[UIView layoutIfNeeded]
或 [UIView updateConstraintsIfNeeded]
- 条件:
!(BOOL)[NSThread isMainThread]
在模拟器上构建和 运行 应用程序并复制导致抛出错误消息的步骤(应用程序将比平时慢!)。 Xcode 然后将停止应用程序并标记从后台线程访问 UI 的代码行(例如调用函数)。
我在同一 ViewController 中尝试更新 UILabel 中的错误消息时遇到了同样的问题(尝试使用正常编码更新数据时需要一些时间)。我在 Swift 3 Xcode 8 中使用了 DispatchQueue
并且有效。
显然您正在对后台线程进行一些 UI 更新。在没有看到您的代码的情况下无法准确预测位置。
这些是可能发生的一些情况:-
您可能正在后台线程上执行某些操作但未使用。在相同的函数中,这段代码更容易被发现。
DispatchQueue.main.async { // do UI update here }
调用一个 func 在后台线程上执行 Web 请求调用,其完成处理程序调用其他 func 执行 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()
}
}
对我来说,问题如下。
确保performSegueWithIdentifier:
在主线程上执行:
dispatch_async (dispatch_get_main_queue(), ^{
[self performSegueWithIdentifier:@"ViewController" sender:nil];
});
Swift 4,
假设,如果您正在使用操作队列调用某些方法
operationQueue.addOperation({
self.searchFavourites()
})
假设函数 searchFavourites 是这样的,
func searchFavourites() {
DispatchQueue.main.async {
//Your code
}
}
如果你在主线程上调用方法 "searchFavourites" 中的所有代码,如果你正在更新其中的某些 UI,它仍然会出错。
This application is modifying the autolayout engine from a background
thread after the engine was accessed from the main thread.
所以使用解决方案,
operationQueue.addOperation({
DispatchQueue.main.async {
self.searchFavourites()
}
})
对于这种场景。
我也遇到了这个问题,当我将 window 的大小调整为小于其初始值时,看到输出中打印了大量这些消息和堆栈跟踪。花了很长时间弄清楚这个问题,我想我会分享一个相当简单的解决方案。我曾经通过 IB 在 NSTextView
上启用 Can Draw Concurrently
。这告诉 AppKit 它可以从另一个线程调用视图的 draw(_:)
方法。禁用它后,我不再收到任何错误消息。在更新到 macOS 10.14 Beta 之前我没有遇到任何问题,但与此同时,我也开始修改代码以执行与文本视图的工作。
如果您想查找此错误,请使用主线程检查程序在出现问题时暂停复选框。
大多数时候修复它很容易,在主队列中调度有问题的行。
"This application is modifying the autolayout engine from a background thread" 的主要问题是它似乎在实际问题发生后很长时间才被记录下来,这使得排除故障变得非常困难。
我通过创建三个符号断点设法解决了这个问题。
调试 > 断点 > 创建符号断点...
断点 1:
符号:-[UIView setNeedsLayout]
条件:!(BOOL)[NSThread isMainThread]
断点 2:
符号:-[UIView layoutIfNeeded]
条件:!(BOOL)[NSThread isMainThread]
断点 3:
符号:-[UIView updateConstraintsIfNeeded]
条件:!(BOOL)[NSThread isMainThread]
使用这些断点,您可以轻松地在您在非主线程上错误地调用 UI 方法的实际行上打断。
在此处查看日志中的这一行
$S12AppName18ViewControllerC11Func()ySS_S2StF + 4420
你可以检查从后台线程调用哪个函数或者你在哪里调用api方法你需要像这样从主线程调用你的函数。
DispatchQueue.main.async { func()}
func() is that function you want to call in the result of api call
success or else.
在此处记录
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
)
在我的 OS X using swift 中经常遇到这个错误:
"This application is modifying the autolayout engine from a background thread, which can lead to engine corruption and weird crashes. This will cause an exception in a future release."
我有一个 NSWindow,我正在将视图交换到 window 的 contentView
。当我尝试在 window 上执行 NSApp.beginSheet
或向 window 添加 subview
时,我得到 error .尝试禁用自动调整大小的东西,但我没有使用自动布局的任何东西。有什么想法吗?
有时它很好但什么也没有发生,其他时候它完全破坏了我的 UI
并且没有任何加载
它需要放在不同的线程中,允许 UI 在线程函数执行完成后立即更新:
现代Swift:
DispatchQueue.main.async {
// Update UI
}
旧版本 Swift,pre Swift 3.
dispatch_async(dispatch_get_main_queue(){
// code here
})
Objective-C:
dispatch_async(dispatch_get_main_queue(), ^{
// code here
});
遇到了同样的问题,因为我使用的是 performSelectorInBackground
。
自从更新到 iOS 9 SDK 后,我遇到了这个问题,当时我正在调用一个在 NSURLConnection 异步请求完成处理程序中执行 UI 更新的块。使用 dispatch_main_queue 将块调用放入 dispatch_async 解决了这个问题。
它在 iOS 8.
中运行良好我在使用 TouchID 时遇到了这个问题,如果这对其他人有帮助,请包装您的成功逻辑,这可能会对主队列中的 UI 执行某些操作。
在不使用 'dispatch_async' 的情况下 使用打印语句 进行调试时,您会收到类似的错误消息 因此,当您收到该错误消息时,是时候使用
Swift 4
DispatchQueue.main.async { //code }
Swift 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"
})
已编辑 - SWIFT 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"
}
}
我遇到了同样的问题。原来我使用的是 UIAlerts
需要主队列。但是,它们已被 弃用 。
当我将 UIAlerts
更改为 UIAlertController
时,我不再有问题并且不必使用任何 dispatch_async
代码。教训——注意警告。即使在您意想不到的时候,它们也会提供帮助。
你一定不能改UI越位主线程! UIKit不是线程安全的,所以如果你这样做会出现上述问题以及其他一些奇怪的问题。该应用程序甚至会崩溃。
所以,要进行UIKit操作,需要定义block,让它在主队列上执行:如,
NSOperationQueue.mainQueue().addOperationWithBlock {
}
它可以像设置文本字段/标签值或在后台线程中添加子视图一样简单,这可能会导致字段布局发生变化。确保您对界面所做的任何操作仅发生在主线程中。
对我而言,此错误消息源自 Admob SDK 的横幅。
通过设置条件断点,我能够将原点追踪到 "WebThread"。
然后我可以通过封装横幅创建来解决这个问题:
dispatch_async(dispatch_get_main_queue(), ^{
_bannerForTableFooter = [[GADBannerView alloc] initWithAdSize:kGADAdSizeSmartBannerPortrait];
...
}
我不知道为什么这有帮助,因为我看不到这段代码是如何从非主线程调用的。
希望对大家有所帮助。
您已经从@Mark 那里获得了正确的代码答案,但是,只是为了分享我的发现: 问题是您请求更改视图并假设它会立即发生。实际上,视图的加载取决于可用资源。如果一切都加载得足够快并且没有延迟,那么您就不会注意到任何事情。在某些情况下,由于进程线程繁忙等原因导致任何延迟,应用程序会遇到一种情况,即它应该显示某些内容,即使它尚未准备好。因此,建议在异步队列中分派这些请求,以便它们根据负载执行。
我在 UITableView 中重新加载数据时遇到了这个问题。只需按如下方式调度重新加载即可解决我的问题。
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.tableView.reloadData()
})
"this application is modifying the autolayout engine from a background thread" 错误在实际问题发生很久之后才记录在控制台中,因此如果不使用断点,调试起来会很困难。
我使用@markussvensson 的回答来检测我的问题并使用这个符号断点(调试 > 断点 > 创建符号断点)找到它:
- 符号:
[UIView layoutIfNeeded]
或[UIView updateConstraintsIfNeeded]
- 条件:
!(BOOL)[NSThread isMainThread]
在模拟器上构建和 运行 应用程序并复制导致抛出错误消息的步骤(应用程序将比平时慢!)。 Xcode 然后将停止应用程序并标记从后台线程访问 UI 的代码行(例如调用函数)。
我在同一 ViewController 中尝试更新 UILabel 中的错误消息时遇到了同样的问题(尝试使用正常编码更新数据时需要一些时间)。我在 Swift 3 Xcode 8 中使用了 DispatchQueue
并且有效。
显然您正在对后台线程进行一些 UI 更新。在没有看到您的代码的情况下无法准确预测位置。
这些是可能发生的一些情况:-
您可能正在后台线程上执行某些操作但未使用。在相同的函数中,这段代码更容易被发现。
DispatchQueue.main.async { // do UI update here }
调用一个 func 在后台线程上执行 Web 请求调用,其完成处理程序调用其他 func 执行 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()
}
}
对我来说,问题如下。
确保performSegueWithIdentifier:
在主线程上执行:
dispatch_async (dispatch_get_main_queue(), ^{
[self performSegueWithIdentifier:@"ViewController" sender:nil];
});
Swift 4,
假设,如果您正在使用操作队列调用某些方法
operationQueue.addOperation({
self.searchFavourites()
})
假设函数 searchFavourites 是这样的,
func searchFavourites() {
DispatchQueue.main.async {
//Your code
}
}
如果你在主线程上调用方法 "searchFavourites" 中的所有代码,如果你正在更新其中的某些 UI,它仍然会出错。
This application is modifying the autolayout engine from a background thread after the engine was accessed from the main thread.
所以使用解决方案,
operationQueue.addOperation({
DispatchQueue.main.async {
self.searchFavourites()
}
})
对于这种场景。
我也遇到了这个问题,当我将 window 的大小调整为小于其初始值时,看到输出中打印了大量这些消息和堆栈跟踪。花了很长时间弄清楚这个问题,我想我会分享一个相当简单的解决方案。我曾经通过 IB 在 NSTextView
上启用 Can Draw Concurrently
。这告诉 AppKit 它可以从另一个线程调用视图的 draw(_:)
方法。禁用它后,我不再收到任何错误消息。在更新到 macOS 10.14 Beta 之前我没有遇到任何问题,但与此同时,我也开始修改代码以执行与文本视图的工作。
如果您想查找此错误,请使用主线程检查程序在出现问题时暂停复选框。 大多数时候修复它很容易,在主队列中调度有问题的行。
"This application is modifying the autolayout engine from a background thread" 的主要问题是它似乎在实际问题发生后很长时间才被记录下来,这使得排除故障变得非常困难。
我通过创建三个符号断点设法解决了这个问题。
调试 > 断点 > 创建符号断点...
断点 1:
符号:
-[UIView setNeedsLayout]
条件:
!(BOOL)[NSThread isMainThread]
断点 2:
符号:
-[UIView layoutIfNeeded]
条件:
!(BOOL)[NSThread isMainThread]
断点 3:
符号:
-[UIView updateConstraintsIfNeeded]
条件:
!(BOOL)[NSThread isMainThread]
使用这些断点,您可以轻松地在您在非主线程上错误地调用 UI 方法的实际行上打断。
在此处查看日志中的这一行
$S12AppName18ViewControllerC11Func()ySS_S2StF + 4420
你可以检查从后台线程调用哪个函数或者你在哪里调用api方法你需要像这样从主线程调用你的函数。
DispatchQueue.main.async { func()}
func() is that function you want to call in the result of api call success or else.
在此处记录
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
)