获取"此应用程序正在从后台线程修改自动布局引擎"错误?

时间:2015-02-03 15:01:18

标签: swift macos autolayout background-thread

使用swift在我的OS X中遇到了很多错误:

  

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

我有一个 NSWindow ,我正在浏览窗口的contentView。当我尝试在窗口上执行NSApp.beginSheet或向窗口添加subview时,我收到错误。尝试禁用自动调整大小的东西,我没有任何使用自动布局的东西。有什么想法吗?

有时一切都很好而且没有任何反应,有时它完全打破我的UI并且没有任何负载

21 个答案:

答案 0 :(得分:611)

好的 - 找到了答案。它需要放在一个不同的线程中,允许UI在线程函数执行完成后立即更新:

Swift 3

 DispatchQueue.main.async {
    // Update UI
 }

Swift版本< 3

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

Objective-C Version

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

答案 1 :(得分:142)

使用打印语句进行调试时,您会收到类似的错误消息,而不使用' dispatch_async' 因此,当您收到该错误消息时,是时候使用

Swift 4

DispatchQueue.main.async { //code }

Swift 3

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

较早的Swift版本

dispatch_async(dispatch_get_main_queue()){ //code }

答案 2 :(得分:69)

使用@markussvensson回答来检测我的问题,使用此符号断点找到它:

  1. 符号:[UIView layoutIfNeeded][UIView updateConstraintsIfNeeded]
  2. 条件:!(BOOL)[NSThread isMainThread]
  3. enter image description here

答案 3 :(得分:25)

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

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

答案 4 :(得分:21)

对我来说,此错误消息来自Admob SDK的横幅广告。

我能够追踪到#34; WebThread"通过设置条件断点。

conditional breakpoint to find who is updating ui from background thread

然后我通过使用以下方法封装Banner创建来解决问题:

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

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

希望它可以帮助任何人。

答案 5 :(得分:19)

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

它在iOS 8中运行良好。

答案 6 :(得分:10)

因为我使用performSelectorInBackground而遇到同样的问题。

答案 7 :(得分:7)

您不得更改主线程越位的UI! UIKit不是线程安全的,所以如果你这样做,就会出现上述问题以及其他一些奇怪的问题。该应用程序甚至可能崩溃。

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

NSOperationQueue.mainQueue().addOperationWithBlock {

}

答案 8 :(得分:6)

显然,你在后台线程上做了一些UI更新。如果没有看到您的代码,就无法准确预测到哪里。

可能会发生以下情况: -

你可能在后台线程上做了一些事情而没有使用。具有相同的功能,这个代码更容易被发现。

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

调用func在后台线程上执行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()
            }
}

答案 9 :(得分:4)

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

我设法通过创建三个符号断点来解决该问题。

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

断点1:

  • 符号:-[UIView setNeedsLayout]

  • 条件:!(BOOL)[NSThread isMainThread]

断点2:

  • 符号:-[UIView layoutIfNeeded]

  • 条件:!(BOOL)[NSThread isMainThread]

断点3:

  • 符号:-[UIView updateConstraintsIfNeeded]

  • 条件:!(BOOL)[NSThread isMainThread]

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

答案 10 :(得分:4)

我在UITableView中重新加载数据时遇到了这个问题。只需按照以下方式调度重新加载就可以解决问题。

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

答案 11 :(得分:3)

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

答案 12 :(得分:3)

我遇到了同样的问题。事实证明我正在使用需要主队列的UIAlerts。但是,他们已被弃用 当我将UIAlerts更改为UIAlertController时,我不再遇到问题而且不必使用任何dispatch_async代码。教训 - 注意警告。即使你不指望它们,它们也会有所帮助。

答案 13 :(得分:2)

这可能就像设置文本字段/标签值或在后台线程中添加子视图一样简单,这可能会导致字段的布局发生变化。确保您对界面所做的任何操作只发生在主线程中。

点击此链接:https://forums.developer.apple.com/thread/7399

答案 14 :(得分:2)

我在尝试在同一个ViewController中更新UILabel中的错误消息时遇到了同样的问题(在尝试使用正常编码时更新数据需要一些时间)。我在Swift 3 Xcode 8中使用DispatchQueue并且它可以工作。

答案 15 :(得分:2)

I had this issue when I was using TouchID if that helps anyone else, wrap your success logic which likely does something with the UI in the main queue.

答案 16 :(得分:1)

对我来说,问题如下。 确保在主线程上执行public void fillListFromDb() { SQLiteDatabase db = new HelpedDb().getReadableDatabase(); Cursor getcityid = db.rawQuery("select * from defcity",null); String tmpcityid = ""; if(getcityid!=null) { if(getcityid.moveToFirst()) { tmpcityid = getcityid.getString(getcityid.getColumnIndex("defvalue")); } } getcityid.close(); Cursor getCityName =db.rawQuery("select * from city where id="+tmpcityid,null); String cityName=""; if(getCityName!=null) { if(getCityName.moveToFirst()) { cityName=getCityName.getString(getCityName.getColumnIndex("cityname")); } } txtcityname = (TextView) findViewById(R.id.txtcityname); txtcityname.setText("("+cityName+")"); getCityName.close(); Cursor cursor = db.rawQuery("select * from dayoghat where cityid="+tmpcityid,null); Intent alarmIntent = new Intent(G.context,Alarm_reciver.class); pendingIntent = PendingIntent.getBroadcast(G.context,0,alarmIntent,PendingIntent.FLAG_UPDATE_CURRENT); Calendar calendar = Calendar.getInstance(); while (cursor.moveToNext()) { StructOghat oghatlist = new StructOghat(); oghatlist.rooz = cursor.getString(cursor.getColumnIndex("rooz")); oghatlist.sahar = cursor.getString(cursor.getColumnIndex("sahar")); oghatlist.azan = cursor.getString(cursor.getColumnIndex("azan")); oghatlist.ramazan = cursor.getString(cursor.getColumnIndex("ramazan")); String currentazan = cursor.getString(cursor.getColumnIndex("azan")); String[] azantime = currentazan.split(":"); int azanhour = Integer.parseInt(azantime[0]); int azanminute = Integer.parseInt(azantime[1]); calendar.set(Calendar.HOUR_OF_DAY,azanhour); calendar.set(Calendar.MINUTE,azanminute); calendar.set(Calendar.SECOND,0); Log.e("azan",azantime[0]); Log.e("azanminut",azantime[1]); alarmManager=(AlarmManager) getSystemService(ALARM_SERVICE); alarmManager.set(AlarmManager.RTC_WAKEUP,calendar.getTimeInMillis(),pendingIntent); list.add(oghatlist); } adapter.notifyDataSetChanged(); } }

performSegueWithIdentifier:

答案 17 :(得分:1)

Swift 4,

假设您正在使用操作队列调用某个方法

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

假设函数searchFavourites就像,

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

如果你在主线程上调用方法“searchFavourites”中的所有代码,如果你正在更新其中的一些UI,它仍然会给出错误。

  

此应用程序正在从后台修改autolayout引擎   从主线程访问引擎后的线程。

所以使用解决方案,

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

对于这种情况。

答案 18 :(得分:1)

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

enter image description here

答案 19 :(得分:0)

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

答案 20 :(得分:0)

从日志中查看此行

$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
)