【问题标题】:How to trap on UIViewAlertForUnsatisfiableConstraints?如何捕获 UIViewAlertForUnsatisfiableConstraints?
【发布时间】:2014-12-10 22:15:00
【问题描述】:

我看到调试器日志中出现错误:

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x191f0920 H:[MPKnockoutButton:0x17a876b0]-(34)-[MPDetailSlider:0x17a8bc50](LTR)>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.

我如何在那个电话中被困住?它没有出现在我的代码中。

【问题讨论】:

  • 10 例中有 9 例:这只是由于:对于 yoru 故事板上的某些视图或项目,您取消选中“已安装”。 (例如,只是一个开发按钮或您不再需要的东西。)一般来说,它处理“未安装”很糟糕:它经常在那里留下约束,如果没有未安装的项目,这些约束变得毫无意义。通常,解决方案只是删除您忘记的项目,即“未安装”的项目 - 只需删除它们。

标签: ios autolayout uikit constraints xcode7


【解决方案1】:

这个post 帮助了我很多

我添加了 UIViewAlertForUnsatisfiableConstraints 带有建议操作的符号断点:

Obj-C 项目

po [[UIWindow keyWindow] _autolayoutTrace]

Swift 项目

expr -l objc++ -O -- [[UIWindow keyWindow] _autolayoutTrace]

有了这个提示,日志变得更加详细,我更容易识别出哪个视图的约束被破坏了。

UIWindow:0x7f88a8e4a4a0
|   UILayoutContainerView:0x7f88a8f23b70
|   |   UINavigationTransitionView:0x7f88a8ca1970
|   |   |   UIViewControllerWrapperView:0x7f88a8f2aab0
|   |   |   |   •UIView:0x7f88a8ca2880
|   |   |   |   |   *UIView:0x7f88a8ca2a10
|   |   |   |   |   |   *UIButton:0x7f88a8c98820'Archived'
|   |   |   |   |   |   |   UIButtonLabel:0x7f88a8cb0e30'Archived'
|   |   |   |   |   |   *UIButton:0x7f88a8ca22d0'Download'
|   |   |   |   |   |   |   UIButtonLabel:0x7f88a8cb04e0'Download'
|   |   |   |   |   |   *UIButton:0x7f88a8ca1580'Deleted'
|   |   |   |   |   |   |   UIButtonLabel:0x7f88a8caf100'Deleted'
|   |   |   |   |   *UIView:0x7f88a8ca33e0
|   |   |   |   |   *_UILayoutGuide:0x7f88a8ca35b0
|   |   |   |   |   *_UILayoutGuide:0x7f88a8ca4090
|   |   |   |   |   _UIPageViewControllerContentView:0x7f88a8f1a390
|   |   |   |   |   |   _UIQueuingScrollView:0x7f88aa031c00
|   |   |   |   |   |   |   UIView:0x7f88a8f38070
|   |   |   |   |   |   |   UIView:0x7f88a8f381e0
|   |   |   |   |   |   |   |   •UIView:0x7f88a8f39fa0, MISSING HOST CONSTRAINTS
|   |   |   |   |   |   |   |   |   *UIButton:0x7f88a8cb9bf0'Retrieve data'- AMBIGUOUS LAYOUT for UIButton:0x7f88a8cb9bf0'Retrieve data'.minX{id: 170}, UIButton:0x7f88a8cb9bf0'Retrieve data'.minY{id: 171}
|   |   |   |   |   |   |   |   |   *UIImageView:0x7f88a8f3ad80- AMBIGUOUS LAYOUT for UIImageView:0x7f88a8f3ad80.minX{id: 172}, UIImageView:0x7f88a8f3ad80.minY{id: 173}
|   |   |   |   |   |   |   |   |   *App.RecordInfoView:0x7f88a8cbe530- AMBIGUOUS LAYOUT for App.RecordInfoView:0x7f88a8cbe530.minX{id: 174}, App.RecordInfoView:0x7f88a8cbe530.minY{id: 175}, App.RecordInfoView:0x7f88a8cbe530.Width{id: 176}, App.RecordInfoView:0x7f88a8cbe530.Height{id: 177}
|   |   |   |   |   |   |   |   |   |   +UIView:0x7f88a8cc1d30- AMBIGUOUS LAYOUT for UIView:0x7f88a8cc1d30.minX{id: 178}, UIView:0x7f88a8cc1d30.minY{id: 179}, UIView:0x7f88a8cc1d30.Width{id: 180}, UIView:0x7f88a8cc1d30.Height{id: 181}
|   |   |   |   |   |   |   |   |   |   |   *UIView:0x7f88a8cc1ec0- AMBIGUOUS LAYOUT for UIView:0x7f88a8cc1ec0.minX{id: 153}, UIView:0x7f88a8cc1ec0.minY{id: 151}, UIView:0x7f88a8cc1ec0.Width{id: 154}, UIView:0x7f88a8cc1ec0.Height{id: 165}
|   |   |   |   |   |   |   |   |   |   |   |   *UIView:0x7f88a8e68e10- AMBIGUOUS LAYOUT for UIView:0x7f88a8e68e10.minX{id: 155}, UIView:0x7f88a8e68e10.minY{id: 150}, UIView:0x7f88a8e68e10.Width{id: 156}
|   |   |   |   |   |   |   |   |   |   |   |   *UIImageView:0x7f88a8e65de0- AMBIGUOUS LAYOUT for UIImageView:0x7f88a8e65de0.minX{id: 159}, UIImageView:0x7f88a8e65de0.minY{id: 182}
|   |   |   |   |   |   |   |   |   |   |   |   *UILabel:0x7f88a8e69080'8-6-2015'- AMBIGUOUS LAYOUT for UILabel:0x7f88a8e69080'8-6-2015'.minX{id: 183}, UILabel:0x7f88a8e69080'8-6-2015'.minY{id: 184}, UILabel:0x7f88a8e69080'8-6-2015'.Width{id: 185}
|   |   |   |   |   |   |   |   |   |   |   |   *UILabel:0x7f88a8cc0690'16:34'- AMBIGUOUS LAYOUT for UILabel:0x7f88a8cc0690'16:34'.minX{id: 186}, UILabel:0x7f88a8cc0690'16:34'.minY{id: 187}, UILabel:0x7f88a8cc0690'16:34'.Width{id: 188}, UILabel:0x7f88a8cc0690'16:34'.Height{id: 189}
|   |   |   |   |   |   |   |   |   |   |   |   *UIView:0x7f88a8cc2050- AMBIGUOUS LAYOUT for UIView:0x7f88a8cc2050.minX{id: 161}, UIView:0x7f88a8cc2050.minY{id: 166}, UIView:0x7f88a8cc2050.Width{id: 163}
|   |   |   |   |   |   |   |   |   |   |   |   *UIImageView:0x7f88a8e69d90- AMBIGUOUS LAYOUT for UIImageView:0x7f88a8e69d90.minX{id: 190}, UIImageView:0x7f88a8e69d90.minY{id: 191}, UIImageView:0x7f88a8e69d90.Width{id: 192}, UIImageView:0x7f88a8e69d90.Height{id: 193}
|   |   |   |   |   |   |   |   |   |   |   *UIView:0x7f88a8f3cc00
|   |   |   |   |   |   |   |   |   |   |   |   *UIView:0x7f88a8e618d0
|   |   |   |   |   |   |   |   |   |   |   |   *UIImageView:0x7f88a8e5ba10
|   |   |   |   |   |   |   |   |   |   |   |   *UIView:0x7f88a8f3cd70
|   |   |   |   |   |   |   |   |   |   |   |   *UIImageView:0x7f88a8e58e10
|   |   |   |   |   |   |   |   |   |   |   |   *UIImageView:0x7f88a8e5e7a0
|   |   |   |   |   |   |   |   |   |   |   |   *UIView:0x7f88a8f3cee0
|   |   |   |   |   |   |   |   |   |   |   *UIView:0x7f88a8f3dc70
|   |   |   |   |   |   |   |   |   |   |   |   *UIView:0x7f88a8e64dd0
|   |   |   |   |   |   |   |   |   |   |   |   *UILabel:0x7f88a8e65290'Average flow rate'
|   |   |   |   |   |   |   |   |   |   |   |   *UILabel:0x7f88a8e712d0'177.0 ml/s'
|   |   |   |   |   |   |   |   |   |   |   |   *UILabel:0x7f88a8c97150'1299.4'
|   |   |   |   |   |   |   |   |   |   |   |   *UIView:0x7f88a8f3dde0
|   |   |   |   |   |   |   |   |   |   |   |   *UILabel:0x7f88a8f3df50'Maximum flow rate'
|   |   |   |   |   |   |   |   |   |   |   |   *UILabel:0x7f88a8cbfdb0'371.6 ml/s'
|   |   |   |   |   |   |   |   |   |   |   |   *UILabel:0x7f88a8cc0230'873.5'
|   |   |   |   |   |   |   |   |   |   |   |   *UIView:0x7f88a8f3e2a0
|   |   |   |   |   |   |   |   |   |   |   |   *UILabel:0x7f88a8f3e410'Total volume'
|   |   |   |   |   |   |   |   |   |   |   |   *UILabel:0x7f88a8cc0f20'371.6 ml'
|   |   |   |   |   |   |   |   |   |   |   |   *UIView:0x7f88a8f3e870
|   |   |   |   |   |   |   |   |   |   |   |   *UILabel:0x7f88a8f3ea00'Time do max. flow'
|   |   |   |   |   |   |   |   |   |   |   |   *UILabel:0x7f88a8cc0ac0'3.6 s'
|   |   |   |   |   |   |   |   |   |   |   |   *UIView:0x7f88a8f3ee10
|   |   |   |   |   |   |   |   |   |   |   |   *UILabel:0x7f88a8f3efa0'Flow time'
|   |   |   |   |   |   |   |   |   |   |   |   *UILabel:0x7f88a8cbf980'2.1 s'
|   |   |   |   |   |   |   |   |   |   |   |   *UIView:0x7f88a8f3f3e0
|   |   |   |   |   |   |   |   |   |   |   |   *UILabel:0x7f88a8f3f570'Voiding time'
|   |   |   |   |   |   |   |   |   |   |   |   *UILabel:0x7f88a8cc17e0'3.5 s'
|   |   |   |   |   |   |   |   |   |   |   |   *UIView:0x7f88a8f3f9a0
|   |   |   |   |   |   |   |   |   |   |   |   *UILabel:0x7f88a8f3fb30'Voiding delay'
|   |   |   |   |   |   |   |   |   |   |   |   *UILabel:0x7f88a8cc1380'1.0 s'
|   |   |   |   |   |   |   |   |   |   |   |   *UIView:0x7f88a8e65000
|   |   |   |   |   |   |   |   |   |   |   |   *UIButton:0x7f88a8e52f20'Show'
|   |   |   |   |   |   |   |   |   |   |   |   *UIImageView:0x7f88a8e6e1d0
|   |   |   |   |   |   |   |   |   |   |   |   *UIButton:0x7f88a8e52c90'Send'
|   |   |   |   |   |   |   |   |   |   |   |   *UIImageView:0x7f88a8e61bb0
|   |   |   |   |   |   |   |   |   |   |   |   *UIButton:0x7f88a8e528e0'Delete'
|   |   |   |   |   |   |   |   |   |   |   |   *UIImageView:0x7f88a8e6b3f0
|   |   |   |   |   |   |   |   |   |   |   |   *UIView:0x7f88a8f3ff60
|   |   |   |   |   |   |   |   |   *UIActivityIndicatorView:0x7f88a8cba080
|   |   |   |   |   |   |   |   |   |   UIImageView:0x7f88a8cba700
|   |   |   |   |   |   |   |   |   *_UILayoutGuide:0x7f88a8cc3150
|   |   |   |   |   |   |   |   |   *_UILayoutGuide:0x7f88a8cc3b10
|   |   |   |   |   |   |   UIView:0x7f88a8f339c0
|   |   UINavigationBar:0x7f88a8c96810
|   |   |   _UINavigationBarBackground:0x7f88a8e45c00
|   |   |   |   UIImageView:0x7f88a8e46410
|   |   |   UINavigationItemView:0x7f88a8c97520'App'
|   |   |   |   UILabel:0x7f88a8c97cc0'App'
|   |   |   UINavigationButton:0x7f88a8e3e850
|   |   |   |   UIImageView:0x7f88a8e445b0
|   |   |   _UINavigationBarBackIndicatorView:0x7f88a8f2b530

Legend:
    * - is laid out with auto layout
    + - is laid out manually, but is represented in the layout engine because translatesAutoresizingMaskIntoConstraints = YES
    • - layout engine host

然后我暂停执行,并用命令更改了有问题的视图的背景颜色(当然,用你的对象的内存地址替换0x7f88a8cc2050)...

Obj-C

expr ((UIView *)0x7f88a8cc2050).backgroundColor = [UIColor redColor]

Swift 3.0

expr -l Swift -- import UIKit
expr -l Swift -- unsafeBitCast(0x7f88a8cc2050, to: UIView.self).backgroundColor = UIColor.red

... 结果太棒了!

简直太棒了! 希望对您有所帮助。

【讨论】:

  • @iAnurag 您可以在执行暂停时在控制台区域运行命令。
  • @TomCalmon 我也做了同样的事情......但它显示以下错误rror: Execution was interrupted, reason: EXC_BAD_ACCESS (code=1, address=0x7f88a8cc2050). The process has been returned to the state before expression evaluation.
  • expr -l objc++ -O -- [[UIWindow keyWindow] _autolayoutTrace] 为我返回 nil
  • 难以置信。这里有很好的提示,完全帮助我直接解决了这个问题。一旦项目变为红色,如果可能继续执行,您将看到高亮显示。
  • 尝试这个时我得到error: Execution was interrupted, reason: internal ObjC exception breakpoint(-5)..
【解决方案2】:

您需要添加Symbolic Breakpoint。 Apple 提供了一个excellent guide 来说明如何执行此操作。

  1. 打开断点导航器cmd+7(Xcode 9 中的cmd+8
  2. 点击左下角的Add按钮
  3. 选择Add Symbolic Breakpoint...
  4. 上面写着Symbol,只需输入UIViewAlertForUnsatisfiableConstraints

您还可以将其视为任何其他断点,打开和关闭它、添加操作或记录消息。

【讨论】:

  • 我只是不明白如何使用此提示更好地调试问题。我添加了一个符号断点,但它仍然没有给我足够的信息是什么问题。唯一的方法是尝试逐行阅读并了解导致问题的原因......否则清除约束并再次将它们与辅助视图中的预览一起添加应该最有帮助!
  • 这可能有助于在断点处停止后获取更多信息:staxmanade.com/2015/06/debugging-ios-autolayout-issues
  • 只需添加,您现在可以直接在 IB 中为约束提供标识符,因此当您调试它们时,您会看到这个名称。
  • (@MarqueIV 的后续)NSLayoutConstraint 自 iOS 7Xcode 7 及更高版本 以来拥有 identifier 属性,其中既可以从 IB Storyboards 也可以从代码中设置。通过设置标识符,您可以更轻松地在调试日志中区分系统生成的约束和用户生成的约束,例如myConstraint.identifier = "centered image"(来源和示例:useyourloaf.com/blog/using-identifiers-to-debug-autolayout
  • @AlexCio 它有什么帮助?它至少会在它发生的那一刻暂停。它提供了一个堆栈跟踪,您可以在其中回溯并找到原点...
【解决方案3】:

听从斯蒂芬的建议并尝试调试代码,哇!有效。答案在于调试消息本身。

Will attempt to recover by breaking constraint NSLayoutConstraint:0x191f0920 H:[MPKnockoutButton:0x17a876b0]-(34)-[MPDetailSlider:0x17a8bc50](LTR)>

上面的行告诉您运行时通过删除此约束来工作。可能您的按钮 (MPKnockoutButton) 上不需要水平间距。一旦你清除了这个约束,它就不会在运行时抱怨并且你会得到想要的行为。

【讨论】:

  • 编译器?你是说运行时间?编译器没有删除约束。编译器将其留给运行时处理,因此“通过打破约束恢复”在运行时
【解决方案4】:

每当我尝试删除系统必须打破的约束时,我的约束不再足以满足 IB(即“缺少约束”在 IB 中显示,这意味着它们不完整并且不会被使用)。实际上,我通过将它想要打破的约束设置为低优先级来解决这个问题,这(这是一个假设)允许系统优雅地打破约束。这可能不是最好的解决方案,但它解决了我的问题,并且由此产生的约束效果很好。

【讨论】:

  • 通常情况下,您希望使用在运行时删除的占位符约束。要使约束成为占位符约束,请转到约束检查器并单击“在构建时删除”。请注意 IB 绘图区域中的约束工字梁符号如何从蓝色变为灰色以表示这一点。
  • 我遇到了同样的问题。当我删除损坏的约束时,我的设计就坏了。所以我将优先级设置为中等。
【解决方案5】:

这通常在您想在 iPad 中使用 UIActivityViewController 时出现。

在您出示控制器以标记箭头之前添加以下内容。

activityViewController.popoverPresentationController?.sourceRect = senderView.frame // senderView can be your button/view you tapped to call this VC

我假设你已经有下面,如果没有,加在一起:

activityViewController.popoverPresentationController?.sourceView = self.view

【讨论】:

    【解决方案6】:

    我认为我遇到的问题是当我看到这样的事情时:

    (
        "<NSLayoutConstraint:0x600002faf7a0 'UISV-alignment' UIStackView:0x7fcdda716770.top == UIStackView:0x7fcdda7291d0.top   (active)>",
        "<NSLayoutConstraint:0x600002f84dc0 'UISV-canvas-connection' UILayoutGuide:0x6000035a8620'UIViewLayoutMarginsGuide'.top == UILabel:0x7fcdda716900.top   (active)>",
        "<NSLayoutConstraint:0x600002f8dfe0 'UISV-spacing' V:[UIImageView:0x7fcdda7170c0]-(2)-[UIStackView:0x7fcdda7291d0]   (active)>",
        "<NSLayoutConstraint:0x600002f84e60 'UISV-spacing' V:[UILabel:0x7fcdda716900]-(2)-[UIImageView:0x7fcdda7170c0]   (active)>",
        "<NSLayoutConstraint:0x600002f84c80 'UIView-topMargin-guide-constraint' V:|-(20)-[UILayoutGuide:0x6000035a8620'UIViewLayoutMarginsGuide']   (active, names: '|':UIStackView:0x7fcdda716770 )>"
    )
    

    我想,嗯。他们并不真的指望我来处理这些垃圾……但也许这就是我们得到的全部,也许还不错。

    让我们稍微分解一下,代码指的是约束的 id。您实际上可以通过简单地打印出您的约束来找出它们对应的约束,如下所示:

    print("my Constraint", ibOutletConstraint)
    

    你会得到:

    my Constraint Optional(<NSLayoutConstraint:0x600001625a90 UIStackView:0x7fdca0c0d1f0.width == 2*UIStackView: 0x7fcdda716770.width   (inactive)>)
    

    现在我可以获取:0x7fcdda716770 并搜索我的输出以将其与相关约束相匹配。它乏味,当然不光彩,但它是一种逐步分解它的方法。我认为 Apple 确实应该更清楚地说明哪个约束存在问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-08-18
      • 1970-01-01
      • 2013-09-19
      • 2012-03-27
      • 2021-12-11
      • 1970-01-01
      • 2017-10-06
      • 2021-06-15
      相关资源
      最近更新 更多