收到“此应用程序正在从后台线程修改自动布局引擎”错误?


310

使用swift在我的OS X中经常遇到此错误:

“此应用程序正在从后台线程修改自动布局引擎,这可能导致引擎损坏和奇怪的崩溃。这将在以后的版本中引发异常。”

我有一个NSWindow,并且正在交换视图到contentView窗口的视图。尝试在窗口上执行操作或在窗口上添加操作时,都会收到错误消息。试图禁用自动调整大小的东西,并且我没有使用自动布局的东西。有什么想法吗?NSApp.beginSheetsubview

有时候很好,什么也没发生,其他时候却完全破坏了我UI,没有负载


2
出于某种原因,下面一个很好的答案被删除: github.com/nrbrook/NBUIKitMainThreadGuard
Fattie

至少救了我几个小时。感谢@Fattie
oyalhi

对@oyalhi。小心使用它,我真的很喜欢它,但同时也遇到了其他问题-这是一个艰难的领域!希望能帮助到你!
Fattie

一个半相关的问题
亲爱的,

Answers:


638

需要将其放置在不同的线程中,以便在线程功能执行完成后立即更新UI:

现代雨燕:

DispatchQueue.main.async {
    // Update UI
}

较早版本的Swift,低于Swift 3。

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

目标C:

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

3
为了使它在目标C中起作用,请将^(void)放在代码块中的{之前,并使用分号后缀。
2015年

4
虽然没有什么坏处,但不需要^(void)而不是仅仅^。答案的Objective-C版本就可以了。
凯勒2015年

2
这对我来说可以。对于我的问题是,请执行网络请求,并在成功完成模块内部调用函数来更新UI。由于UIKit不是线程安全的,因此需要分派回主线程来更新UI。
雷切尔

1
查看@Naishta的Swift 3解决方案答案
Nathaniel

1
对于Swift 3:DispatchQueue.main.async(){ 代码 },如@Naishta所说
smukamuka

146

在不使用'dispatch_async'的情况下使用打印语句进行调试时,您会收到类似的错误消息,因此当您收到该错误消息时,它的使用时间

斯威夫特4

DispatchQueue.main.async { //code }

迅捷3

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

早期的Swift版本

dispatch_async(dispatch_get_main_queue()){ //code }

5
因为语法错误,应该是: dispatch_async(dispatch_get_main_queue(), ^{ /* UI related code */ });编辑:我更新了他的答案,语法格式在那里效果更好。
佐尔坦

1
或,当在闭包内部时,使用以下命令从后台线程进入主线程:self.performSelectorOnMainThread(Selector(“ yourFunction:”),withObject:'yourArray / yourObject',waitUntilDone:true)
Naishta,2016年

1
不,不是的,请看一下语法
Naishta

82

实际问题发生很长时间之后,在控制台中记录了“此应用程序正在从后台线程修改自动布局引擎”错误,因此在不使用断点的情况下很难调试。

我使用@markussvensson的答案来检测我的问题,并使用以下符号断点(调试>断点>创建符号断点)找到了问题:

  1. 符号:[UIView layoutIfNeeded][UIView updateConstraintsIfNeeded]
  2. 健康)状况: !(BOOL)[NSThread isMainThread]

在此处输入图片说明

在模拟器上构建并运行该应用程序,并复制导致引发错误消息的步骤(该应用程序将比平时慢!)。然后,Xcode将停止应用程序,并标记从后台线程访问UI的代码行(例如,函数的调用)。


3
嗯 我赞成这一点,因为这似乎很有意义。但是,执行没有中断,并且我的日志中仍然出现错误。我还有其他条件可以用来设置符号断点吗?
Sjakelien

就我而言,它确实坏了。但是,堆栈跟踪不会给我任何提示哪个视图负责。而且我不知道如何解释所示的汇编代码movq 0x10880ba(%rip), %rsi ; "_wantsReapplicationOfAutoLayoutWithLayoutDirtyOnEntry:"
ReinhardMänner17年

调试时是否会导致应用严重运行缓慢?
Itachi

@Itachi是的。不知道如何加速。
k06a

2
从Xcode 9开始,它是一个内置功能。只要确保“主线程检查器”选项,在“诊断”的方案设置选项卡启用
AndrewPo

24

当您尝试更新文本字段值或在后台线程内添加子视图时,您可能会遇到此问题。因此,您应将此类代码放入主线程中。

您需要使用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"
   }
}

23

对我而言,此错误消息源自Admob SDK的横幅。

通过设置条件断点,我能够将原点跟踪到“ WebThread”。

有条件断点以查找谁正在从后台线程更新ui

然后,我可以通过将Banner创建封装为以下内容来解决此问题:

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

我不知道为什么这样做有帮助,因为我看不到如何从非主线程调用此代码。

希望它可以帮助任何人。


1
我有同样的问题。我很困惑为什么在WebThread中发生异常。我做了与您相同的更改,现在可以使用了。我使用的是admob sdk的过时版本。我想知道它是否已在最新版本中得到纠正。谢谢你 我认为我不会找到它。
拉里

1
更新至最新版本的AdMob为我解决了这个问题
JH95 '16

我在这样的符号断点处中断,但未显示代码。:(
Victor Engel

20

自从我在调用在NSURLConnection异步请求完成处理程序中执行UI更新的代码块时更新到iOS 9 SDK以来,就遇到了这个问题。通过使用dispatch_main_queue将块调用放入dispatch_async中可以解决此问题。

在iOS 8中运行正常。


10

由于我使用,出现了同样的问题performSelectorInBackground


不,我需要在后台执行操作。我将NSNotificationCenter调用放入了dispatch_async(dispatch_get_main_queue()方法中,并且它起作用了。)
Bobby

我从URLSessionDelegate获取数据,然后将其称为NSNotification,UIViewController对通知进行了响应,在那里我使用DispatchQueue.main.async向用户显示数据是否良好。错误!-解决方案是将Notification放入主队列。DispatchQueue.main.async {NotificationCenter.default.post(名称:NSNotification.Name(rawValue:networkNotificationNames.products.rawValue),对象:self,userInfo:[networkNotificationNames.products.rawValue:productList])}
iCyber​​Paul

7

您不得在主线程之外更改UI!UIKit并不是线程安全的,因此如果您这样做,将会出现上述问题以及其他一些奇怪的问题。该应用程序甚至可能崩溃。

因此,要执行UIKit操作,您需要定义块并让其在主队列上执行:例如,

NSOperationQueue.mainQueue().addOperationWithBlock {

}

这在Xcode 7.2和iOS 9.2中不可用。还有其他选择吗?
Jayprakash Dubey

7

显然,您正在对后台线程进行一些UI更新。无法准确预测位置,而看不到您的代码。

以下是一些可能发生的情况:

您可能正在后台线程上做某事而不使用。由于具有相同的功能,因此该代码更容易发现。

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

在后台线程上调用一个执行Web请求的func调用,其完成处理程序在执行ui更新时调用另一个func。要解决此问题,请尝试在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()
            }
}

5

“此应用程序正在从后台线程修改自动布局引擎”的主要问题是,似乎在实际问题发生后很长时间才被记录下来,这会使故障排除非常困难。

通过创建三个符号断点,我设法解决了这个问题。

调试>断点>创建符号断点...

断点1:

  • 符号: -[UIView setNeedsLayout]

  • 健康)状况: !(BOOL)[NSThread isMainThread]

断点2:

  • 符号: -[UIView layoutIfNeeded]

  • 健康)状况: !(BOOL)[NSThread isMainThread]

断点3:

  • 符号: -[UIView updateConstraintsIfNeeded]

  • 健康)状况: !(BOOL)[NSThread isMainThread]

有了这些断点,您就可以轻松地在错误地调用非主线程上的UI方法的实际行上中断。


4

在UITableView中重新加载数据时遇到了这个问题。只需按以下方式分派重载即可解决此问题。

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

这是给我的!除了杂乱的reloadData()外,我在主队列上还有其他所有东西!
Oprimus

3

我有同样的问题。原来我正在使用UIAlerts所需的主队列。但是,它们已被弃用
当我改变了UIAlertsUIAlertController,我不再有这个问题,并没有使用任何dispatch_async代码。本课-注意警告。即使您不期望它们,它们也可以提供帮助。


3

您已经从@Mark得到了正确的代码答案,但只是为了分享我的发现:问题是,您正在请求视图中的更改并假定更改将立即发生。实际上,视图的加载取决于可用资源。如果一切加载得足够快并且没有延迟,那么您就不会注意到任何事情。在由于进程线程繁忙等原因而导致任何延迟的情况下,该应用程序会遇到这样一种情况,即使该应用程序尚未准备就绪,它也应该显示某些内容。因此,建议将这些请求分派到异步队列中,以便根据负载执行这些请求。


2

我在使用TouchID时遇到了这个问题,如果它可以帮助其他人,请包装您的成功逻辑,这可能会对主队列中的UI产生影响。



2

尝试在同一ViewController中的UILabel中更新错误消息时,我遇到了相同的问题(尝试使用常规编码来更新数据时需要花费一些时间)。我DispatchQueue在Swift 3 Xcode 8中使用了它,并且有效。


2

如果要查找此错误,请使用“主线程检查器在问题上暂停”复选框。大多数情况下,修复起来很容易,将有问题的线路分配到主队列中。

在此处输入图片说明


1
这到底是做什么的?默认情况下,“主线程检查器”处于启用状态,我还同时检查了“主线程检查器”和“问题暂停”,但是它仍然仅抛出“从后台线程修改”消息,而没有添加任何更多信息。
Neph

它会在后台线程中修改UI时暂停应用程序的执行。
rockdaswift

很奇怪,在我的应用程序(Xcode 10.2.1)中没有做到这一点。我不得不手动添加断点(如描述这里)得到它的暂停和代码行点我。
Neph

我该怎么做才能看到这套选项?
David Rector

编辑目标方案
rockdaswift

1

对我来说,问题如下。确保performSegueWithIdentifier:在主线程上执行:

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

1

斯威夫特4

假设,如果您正在使用操作队列调用某些方法

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

假设函数searchFavourites就像,

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

如果调用主线程上方法“ searchFavourites”内的所有代码,则在其中更新某些UI时仍会给出错误。

从主线程访问引擎后,此应用程序正在从后台线程修改自动布局引擎。

所以用溶液

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

对于这种情况。


1

在这里从日志中查看这一行

$S12AppName18ViewControllerC11Func()ySS_S2StF + 4420

您可以检查是从后台线程中调用哪个函数,还是从哪里调用api方法,您需要像这样从主线程中调用函数。

DispatchQueue.main.async { func()}

func()是要在api调用成功或其他情况下调用的函数。

在这里记录

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
)

0

当我将窗口的大小调整为小于其初始值的大小时,我也遇到了这个问题,看到在输出中打印了大量的这些消息和堆栈跟踪。花了很长时间找出问题所在,我认为我会分享一个相当简单的解决方案。我曾使Can Draw ConcurrentlyNSTextView通过IB。这告诉AppKit它可以draw(_:)从另一个线程调用视图的方法。禁用它之后,我不再收到任何错误消息。在更新到macOS 10.14 Beta之前,我没有遇到任何问题,但是与此同时,我也开始修改代码以执行文本视图工作。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.