Як потрапити в пастку на UIViewAlertForUnsatisfiableConstraints?


234

У моєму журналі налагодження з’являється помилка:

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.

Як я вловлюю цей дзвінок? Він не з’являється ніде в моєму коді.

Скріншот1


У 9 з 10 випадків: це просто спричинено: для деякого перегляду чи елемента на аркуші розкадрівки yoru ви знімаєте прапорець "Установлено". (Наприклад, просто кнопка розробки або щось, що вам більше не потрібно.) Загалом, вона погано обробляє "не встановлений": часто залишає там обмеження, які втрачають сенс без не встановленого елемента. Найчастіше рішення полягає в тому, щоб просто видалити елементи, про які ви забули, які сидять навколо "не встановлених" - просто видаліть їх.
Fattie

Відповіді:


442

Цей пост мені допоміг МНОГО !

Я додав символічну точку перерви UIViewAlertForUnsatisfiableConstraints із запропонованою дією:

Проект Obj-C

po [[UIWindow keyWindow] _autolayoutTrace]

Символічна точка розриву з власною дією в проекті Objective-C

Швидкий проект

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

... і результат Це було приголомшливо!

Підказка

Просто дивовижно! Сподіваюся, що це допомагає.


3
@iAnurag Ви можете запускати команди в області консолі, коли виконання призупинено.
Томас Кальмон

2
@TomCalmon Я зробив те саме ... але він показує таку помилку rror: Execution was interrupted, reason: EXC_BAD_ACCESS (code=1, address=0x7f88a8cc2050). The process has been returned to the state before expression evaluation.
iAnurag

2
expr -l objc++ -O -- [[UIWindow keyWindow] _autolayoutTrace]повертається nilдля мене
Ігор Андрєєв

2
Переконайтесь, що ви замінили 0x7f88a8cc2050 адресою пам'яті вашого об'єкта та запустили команду в консолі, коли виконання пауз.
Том Говард

3
Невимовно, неймовірно. Чудова порада тут, повністю допомогла мені перейти до проблеми. Як тільки елемент буде змінено на червоний, продовжте виконання, якщо це можливо, і ви побачите виділення.
Аарон

255

Ви хочете додати Symbolic Breakpoint. Apple пропонує чудовий посібник, як це зробити.

  1. Відкрийте навігатор точки зупинки cmd+7( cmd+8в Xcode 9)
  2. Натисніть Addкнопку внизу ліворуч
  3. Виберіть Add Symbolic Breakpoint...
  4. Там, де написано, Symbolпросто введітьUIViewAlertForUnsatisfiableConstraints

Ви також можете поводитись з нею як з будь-якою іншою точкою розриву, включаючи та вимикаючи, додаючи дії чи повідомлення журналу.


55
Я просто не розумію, як я можу краще налагодити проблему за допомогою цього підказки. Я додав символічну точку розриву, але вона все ще не дає мені достатньо інформації, у чому проблема. Єдиний спосіб - спробувати прочитати рядок за рядком і зрозуміти, що викликає проблему .... інакше очищення обмежень і повторне додавання їх разом з Попереднім переглядом у вікні asisstent повинно допомогти найбільше!
Алекс Ціо

11
Це може допомогти отримати більше інформації після зупинки на точці зламу
fabb

1
Просто додавши, що тепер ви можете давати ідентифікатори обмежень безпосередньо в ІБ, тож коли ви їх налагодите, це ім’я ви побачите.
Марк А. Донохое

2
(продовження на @MarqueIV) NSLayoutConstraintмає identifierвластивість з iOS 7 - Xcode 7 і вище , яку можна встановити як з IB Storyboards, так і з коду. Встановивши ідентифікатор, ви можете простіше розрізнити обмеження, створені системою, та створені користувачем у журналі налагодження, наприклад myConstraint.identifier = "centered image"(джерело та приклади: useyourloaf.com/blog/using-identifiers-to-debug-autolayout )
PDK

@AlexCio Як це допомагає? Найменше - це робити паузи в той момент, коли це відбувається. Це дає сліди стека, де можна відслідковувати та знаходити походження ...
Мед

10

Дотримуйтесь порад Стівена і спробував налагодити код і щоправда! це спрацювало. Відповідь лежить у самому повідомленні про налагодження.

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

Рядок вище вказує вам, що час роботи працював, усуваючи це обмеження. Можливо, вам не потрібен горизонтальний пробіл на вашій кнопці (MPKnockoutButton). Як тільки ви очистите це обмеження, воно не буде скаржитися під час виконання, і ви отримаєте бажану поведінку.


3
Компілятор? Ви маєте на увазі час виконання? Компілятор не усунув обмеження. Компілятор залишив його там для виконання часу, тому "відновившись, порушивши обмеження" під час виконання .
drhr

Так, я мав на увазі тривалість виконання
Sategroup

2

Кожного разу, коли я намагаюся усунути обмеження, які довелося зламати системі, моїх обмежень більше не вистачає для задоволення ІБ (тобто в ІБ показано "відсутні обмеження", це означає, що вони неповні і не використовуються). Я насправді обійшов це, встановивши обмеження, яке воно хоче перейти на низький пріоритет, що (і це припущення) дозволяє системі виграшно обмежувати обмеження. Це, мабуть, не найкраще рішення, але воно вирішило мою проблему, і виникаючі обмеження спрацювали чудово.


2
Зазвичай це ситуація, коли потрібно використовувати обмеження заповнення заповнення, яке видаляється під час виконання. Щоб зробити обмеження обмеженням заповнення місця, перейдіть до інспектора обмежень і натисніть "Видалити під час створення". Зверніть увагу на те, як символ обмежувального променя в області малювання IB перетворюється з синього на сірий на позначення цього.
spencery2

1
У мене було те саме питання. коли я знімаю порушене обмеження, моя конструкція зламалася. Тому я встановив пріоритет на середній.
Джеремі П'єднол
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.