Wie kann man UIViewAlertForUnsatisfiableConstraints einfangen?

234

In meinem Debugger-Protokoll wird ein Fehler angezeigt:

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.

Wie fange ich diesen Anruf ab? Es erscheint nirgendwo in meinem Code.

Screenshot1

Maury Markowitz
quelle
In 9 von 10 Fällen: Dies wird nur verursacht durch: Für eine Ansicht oder ein Element im Yoru-Storyboard deaktivieren Sie "Installiert". (Zum Beispiel nur eine Entwicklungsschaltfläche oder etwas, das Sie nicht mehr benötigen.) Im Allgemeinen wird "nicht installiert" schlecht behandelt: Oft bleiben dort Einschränkungen, die ohne das nicht installierte Element bedeutungslos werden. Oft besteht die Lösung darin, einfach vergessene Elemente zu löschen, die sich um "nicht installiert" befinden - löschen Sie sie einfach.
Fattie

Antworten:

442

Dieser Beitrag hat mir geholfen , VIEL !

Ich habe den symbolischen Haltepunkt UIViewAlertForUnsatisfiableConstraints mit der vorgeschlagenen Aktion hinzugefügt :

Obj-C-Projekt

po [[UIWindow keyWindow] _autolayoutTrace]

Symbolischer Haltepunkt mit benutzerdefinierter Aktion im Objective-C-Projekt

Schnelles Projekt

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

Symbolischer Haltepunkt mit benutzerdefinierter Aktion

Mit diesem Hinweis wurde das Protokoll detaillierter und es war für mich einfacher zu identifizieren, in welcher Ansicht die Einschränkung gebrochen war.

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

Dann habe ich die Ausführung angehalten Pause und die Hintergrundfarbe der problematischen Ansicht mit dem Befehl geändert ( natürlich 0x7f88a8cc2050durch die Speicheradresse Ihres Objekts ersetzt ) ...

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

... und das Ergebnis Es war großartig!

Hinweisansicht

Einfach unglaublich! Ich hoffe es hilft.

Thomás Calmon
quelle
3
@iAnurag Sie können Befehle im Konsolenbereich ausführen, wenn die Ausführung angehalten wird.
Thomás Calmon
2
@ TomCalmon Ich habe das gleiche getan ... aber es zeigt folgenden Fehler 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]kehrt nilfür mich zurück
Igor Andreev
2
Stellen Sie sicher, dass Sie 0x7f88a8cc2050 durch die Speicheradresse Ihres Objekts ersetzen und den Befehl in der Konsole ausführen, wenn die Ausführung angehalten wird.
Tom Howard
3
Unglaublich unglaublich. Toller Tipp hier, hat mir total geholfen, direkt zum Thema zu kommen. Wenn das Element in Rot geändert wurde, setzen Sie die Ausführung nach Möglichkeit fort, und Sie sehen die Markierung.
Aaron
255

Sie möchten eine hinzufügen Symbolic Breakpoint. Apple bietet eine hervorragende Anleitung dazu.

  1. Öffnen Sie den Breakpoint Navigator cmd+7( cmd+8in Xcode 9).
  2. Klicken Sie auf die AddSchaltfläche unten links
  3. Wählen Add Symbolic Breakpoint...
  4. Wo es heißt, tippe Symboleinfach einUIViewAlertForUnsatisfiableConstraints

Sie können es auch wie jeden anderen Haltepunkt behandeln, ein- und ausschalten, Aktionen hinzufügen oder Nachrichten protokollieren.

Stephen Furlani
quelle
55
Ich verstehe einfach nicht, wie ich das Problem mit diesem Hinweis besser beheben kann. Ich habe einen symbolischen Haltepunkt hinzugefügt, aber er gibt mir immer noch nicht genügend Informationen über das Problem. Der einzige Weg ist, zeilenweise zu lesen und zu verstehen, was das Problem verursacht. Andernfalls sollte es am meisten helfen, die Einschränkungen zu löschen und sie erneut zusammen mit der Vorschau in der asisstent-Ansicht hinzuzufügen!
Alex Cio
11
Dies könnte helfen, mehr Informationen zu erhalten, nachdem Sie am Haltepunkt angehalten haben
fabb
1
Fügen Sie einfach hinzu, dass Sie den Einschränkungen jetzt direkt in IB Bezeichner geben können. Wenn Sie sie also debuggen, sehen Sie diesen Namen.
Mark A. Donohoe
2
(Follow-up zu @MarqueIV) NSLayoutConstrainthat identifierseit iOS 7 - Xcode 7 und höher eine Eigenschaft , die sowohl über IB Storyboards als auch über Code festgelegt werden kann. Durch Festlegen des Bezeichners können Sie im Debug-Protokoll leichter zwischen vom System generierten und vom Benutzer generierten Einschränkungen unterscheiden, z. B. myConstraint.identifier = "centered image"(Quelle und Beispiele: useyourloaf.com/blog/using-identifiers-to-debug-autolayout )
PDK
@AlexCio Wie hilft es? Das Mindeste ist, dass es in dem Moment pausiert, in dem es passiert. Es gibt eine Stapelspur, in der Sie zurückverfolgen und den Ursprung finden können ...
Honey
10

Befolgen Sie Stephens Rat und versuchen Sie, den Code zu debuggen und whoa! es funktionierte. Die Antwort liegt in der Debug-Nachricht selbst.

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

Die obige Zeile zeigt Ihnen, dass die Laufzeit durch Entfernen dieser Einschränkung funktioniert hat. Möglicherweise benötigen Sie keinen horizontalen Abstand auf Ihrer Schaltfläche (MPKnockoutButton). Sobald Sie diese Einschränkung aufgehoben haben, wird sie zur Laufzeit nicht mehr beanstandet und Sie erhalten das gewünschte Verhalten.

Kategoriegruppe
quelle
3
Der Compiler? Du meinst die Laufzeit? Der Compiler hat die Einschränkung nicht entfernt. Der Compiler ließ sich dort für die Laufzeit zu bewältigen, also „wiederherstellen , indem Zwang zu brechen“ während der Laufzeit .
Drhr
Ja, ich meinte Laufzeit
Sategroup
2

Immer wenn ich versuche, die Einschränkungen zu entfernen, die das System aufheben musste, reichen meine Einschränkungen nicht mehr aus, um den IB zu erfüllen (dh "fehlende Einschränkungen" werden im IB angezeigt, was bedeutet, dass sie unvollständig sind und nicht verwendet werden). Ich habe dies tatsächlich umgangen, indem ich die Einschränkung, die aufgehoben werden soll, auf eine niedrige Priorität gesetzt habe, wodurch (und dies ist eine Annahme) das System die Einschränkung ordnungsgemäß aufheben kann. Es ist wahrscheinlich nicht die beste Lösung, aber es hat mein Problem gelöst und die daraus resultierenden Einschränkungen haben perfekt funktioniert.

Nick Molyneux
quelle
2
In der Regel möchten Sie eine Platzhaltereinschränkung verwenden, die zur Laufzeit entfernt wird. Um eine Einschränkung zu einer Platzhaltereinschränkung zu machen, rufen Sie den Einschränkungsinspektor auf und klicken Sie auf "Zur Erstellungszeit entfernen". Beachten Sie, wie sich das Symbol für den Einschränkungs-I-Strahl im IB-Zeichenbereich von blau nach grau ändert, um dies anzuzeigen.
spencery2
1
Ich hatte das gleiche Problem. Als ich die gebrochene Einschränkung entfernte, brach mein Design. Also habe ich die Priorität auf mittel gesetzt.
Jeremy Piednoel