iOS9此应用程序正在从后台线程修改autolayout引擎,这可能导致引擎损坏和奇怪的崩溃 [英] iOS9 This application is modifying the autolayout engine from a background thread, which can lead to engine corruption and weird crashes

查看:2456
本文介绍了iOS9此应用程序正在从后台线程修改autolayout引擎,这可能导致引擎损坏和奇怪的崩溃的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚刚下载了最新的XCode(7.1测试版),并开始使用iOS9。

I have just dowloaded the latest XCode (7.1 beta) and have started playing around with iOS9.

我有一个应用程序完美运行,iOS8没有错误但现在我从UITableViewCell类中覆盖drawRect方法得到以下错误:

I had an app working perfectly with no errors in iOS8 but now I get the following error from overriding the drawRect method in a UITableViewCell class :

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

"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."

这里是回溯:

Stack:(
0   CoreFoundation                      0x000000010a749f65 __exceptionPreprocess + 165
1   libobjc.A.dylib                     0x0000000109dcfdeb objc_exception_throw + 48
2   CoreFoundation                      0x000000010a749e9d +[NSException raise:format:] + 205
3   Foundation                          0x0000000109b442e5 _AssertAutolayoutOnMainThreadOnly + 79
4   Foundation                          0x00000001099a4ece -[NSISEngine withBehaviors:performModifications:] + 31
5   UIKit                               0x000000010b9d425b -[UIView(AdditionalLayoutSupport) _withAutomaticEngineOptimizationDisabledIfEngineExists:] + 58
6   UIKit                               0x000000010b9d4d9e -[UIView(AdditionalLayoutSupport) updateConstraintsIfNeeded] + 254
7   UIKit                               0x000000010b702760 -[UITableViewCellContentView updateConstraintsIfNeeded] + 185
8   UIKit                               0x000000010b9d5ab3 -[UIView(AdditionalLayoutSupport) _updateConstraintsAtEngineLevelIfNeeded] + 272
9   UIKit                               0x000000010b1e6274 -[UIView(Hierarchy) _updateConstraintsAsNecessaryAndApplyLayoutFromEngine] + 159
10  UIKit                               0x000000010b1f5d84 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 710
11  QuartzCore                          0x000000010ae1059a -[CALayer layoutSublayers] + 146
12  QuartzCore                          0x000000010ae04e70 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 366
13  QuartzCore                          0x000000010ae04cee _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 24
14  QuartzCore                          0x000000010adf9475 _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 277
15  QuartzCore                          0x000000010ae26c0a _ZN2CA11Transaction6commitEv + 486
16  QuartzCore                          0x000000010ae2737c _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv + 92
17  CoreFoundation                      0x000000010a675967 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23
18  CoreFoundation                      0x000000010a6758d7 __CFRunLoopDoObservers + 391
19  CoreFoundation                      0x000000010a66ae4c CFRunLoopRunSpecific + 524
20  CoreFoundation                      0x000000010a71e011 CFRunLoopRun + 97
21  SDWebImage                          0x000000010971773c -[SDWebImageDownloaderOperation start] + 1868
22  Foundation                          0x0000000109961e47 __NSOQSchedule_f + 194
23  libdispatch.dylib                   0x000000010d93849b _dispatch_client_callout + 8
24  libdispatch.dylib                   0x000000010d91e8ec _dispatch_queue_drain + 2215
25  libdispatch.dylib                   0x000000010d91de0d _dispatch_queue_invoke + 601
26  libdispatch.dylib                   0x000000010d920a56 _dispatch_root_queue_drain + 1420
27  libdispatch.dylib                   0x000000010d9204c5 _dispatch_worker_thread3 + 111
28  libsystem_pthread.dylib             0x000000010dc80a9d _pthread_wqthread + 729
29  libsystem_pthread.dylib             0x000000010dc7e3dd start_wqthread + 13
)

这是drawRect方法:

Here is the drawRect Method :

override func drawRect(rect: CGRect) {

    super.drawRect(rect)

    let cellRect = rect

    // Values
    let buttonBoxX = CELL_MARGIN + CELL_MARGIN/2
    let buttonBoxY = cellRect.height - buttonBoxHeight
    let buttonBoxWidth = rect.width - CELL_MARGIN * 3


    // Set Button Box
    let buttonBoxRect = CGRectMake(buttonBoxX, buttonBoxY, buttonBoxWidth, buttonBoxHeight )
    let buttonBox = UIBezierPath(roundedRect: buttonBoxRect, byRoundingCorners: [.BottomRight, .BottomLeft], cornerRadii: CGSize(width: CORNER_RADIUS, height: CORNER_RADIUS)) // Create the path
    UIColor.whiteColor().setFill() // Set the Fill to be white

    buttonBox.fill()


}

我的理解(参见此问题)是复杂的计算等应该在后台线程和主线程上的UI更新,因为UI不是线程安全的。

My understanding (cf. this question) is that complicated calculations etc should be done on a background thread and the the update of the UI on the main thread because UI is not thread safe.

但是,如果我使用以下:

However, IF i use the following :

override func drawRect(rect: CGRect) {

    super.drawRect(rect)

    let cellRect = rect

    // Values
    let buttonBoxX = CELL_MARGIN + CELL_MARGIN/2
    let buttonBoxY = cellRect.height - buttonBoxHeight
    let buttonBoxWidth = rect.width - CELL_MARGIN * 3


    // Set Button Box
    let buttonBoxRect = CGRectMake(buttonBoxX, buttonBoxY, buttonBoxWidth, buttonBoxHeight )
    let buttonBox = UIBezierPath(roundedRect: buttonBoxRect, byRoundingCorners: [.BottomRight, .BottomLeft], cornerRadii: CGSize(width: CORNER_RADIUS, height: CORNER_RADIUS)) // Create the path
    UIColor.whiteColor().setFill() // Set the Fill to be white

    dispatch_async(dispatch_get_main_queue(), {
        buttonBox.fill()
    })


}

我现在得到一个CGContext错误...

I now get a CGContext error…

<Error>: CGContextSaveGState: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.
<Error>: CGContextSetFlatness: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.
<Error>: CGContextAddPath: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.
<Error>: CGContextDrawPath: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.
<Error>: CGContextRestoreGState: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.
<Error>: CGContextSaveGState: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.
<Error>: CGContextSetFlatness: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.
<Error>: CGContextAddPath: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.
<Error>: CGContextDrawPath: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.
<Error>: CGContextRestoreGState: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.

有什么建议吗?

解决方案:
好​​的。这是交易。我正在异步地将图像加载到UIImageView中,但不是在主线程的UI中绘制它,而是在后台线程上。此外;在将图像添加到UI后,我在UITableViewCell上调用setNeedsDisplay,从而再次调用drawRect方法......但这次是在后台线程上。

SOLUTION : OK. here is the deal. I was loading an image into a UIImageView asynchronously, but not "painting" it in the UI on the main thread but on a background thread. Furthermore; I was calling setNeedsDisplay on the UITableViewCell after adding the image to the UI, thus calling the drawRect method again… but this time on the background thread.

推荐答案

您注意到的第一个错误看起来与您的 drawRect无关:代码。你的 drawRect:看起来很好。它没有做任何特别复杂的事情。如果你的路径更复杂,你可能想要缓存它,但它可能很好。您更有可能尝试在后台线程的其他位置修改UI。它可能只会在您覆盖 drawRect:时弹出,因为它会更改UI更新的发生方式(没有自定义 drawRect: ,系统可能能够应用简单的变换)。您需要查找在后台线程上进行UIKit调用的位置。

The first error you note doesn't look like it's related to your drawRect: code. Your drawRect: looks fine. It isn't doing anything particularly complicated. If your path were more complex, you'd probably want to cache it, but it's probably fine as-is. More likely you're trying to modify the UI somewhere else on a background thread. It may only spring up when you override drawRect: because that changes how the UI update happens (without a custom drawRect:, the system may be able to apply simple transforms). You need to look for where you're making a UIKit call on a background thread.

如果有疑问,如果它以 UI开头,你可能无法在后台线程上使用它。这不完全正确(您可以在后台线程上创建 UIBezierPath ,甚至可以将其绘制到非屏幕上下文中),但作为第一个近似值,它是一个好的事情要找。

When in doubt, if it starts with UI, you probably can't use it on a background thread. That's not completely true (you can create a UIBezierPath on a background thread, and you can even draw it into a non-screen context), but as a first approximation, it's a good thing to look for.

此代码完全错误:

dispatch_async(dispatch_get_main_queue(), {
    buttonBox.fill()
})

drawRect:的调用最好已经在主队列上 (因此调度到主队列没有帮助)。如果不是,请参见上文。当这个块执行时,绘制周期结束,因此没有任何上下文可以进入。

The call to drawRect: had better already be on the main queue (so dispatching to the main queue is not helpful). If it's not, see above. By the time this block executes, the draw cycle is over, so there's no context to draw into any more.

这篇关于iOS9此应用程序正在从后台线程修改autolayout引擎,这可能导致引擎损坏和奇怪的崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆