Nie można jednocześnie spełnić ograniczeń, spróbuje odzyskać je przez zerwanie ograniczenia

145

Poniżej znajduje się komunikat o błędzie, który otrzymałem w obszarze debugowania. Działa dobrze i nic się nie dzieje poza tym, że otrzymuję ten błąd. Czy to uniemożliwiłoby Apple zaakceptowanie aplikacji? Jak to naprawić?

2012-07-26 01:58:18.621 Rolo[33597:11303] Unable to simultaneously satisfy constraints.
    Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
    "<NSAutoresizingMaskLayoutConstraint:0x887d630 h=--& v=--& V:[UIButtonLabel:0x886ed80(19)]>",
    "<NSAutoresizingMaskLayoutConstraint:0x887d5f0 h=--& v=--& UIButtonLabel:0x886ed80.midY == + 37.5>",
    "<NSAutoresizingMaskLayoutConstraint:0x887b4b0 h=--& v=--& V:[UIButtonLabel:0x72bb9b0(19)]>",
    "<NSAutoresizingMaskLayoutConstraint:0x887b470 h=--& v=--& UIButtonLabel:0x72bb9b0.midY == - 0.5>",
    "<NSLayoutConstraint:0x72bf860 V:[UILabel:0x72bf7c0(17)]>",
    "<NSLayoutConstraint:0x72c2430 UILabel:0x72bfad0.top == UILabel:0x72bf7c0.top>",
    "<NSLayoutConstraint:0x72c2370 UILabel:0x72c0270.top == UILabel:0x72bfad0.top>",
    "<NSLayoutConstraint:0x72c22b0 V:[UILabel:0x72bf7c0]-(NSSpace(8))-[UIButton:0x886efe0]>",
    "<NSLayoutConstraint:0x72c15b0 V:[UILabel:0x72c0270]-(NSSpace(8))-[UIRoundedRectButton:0x72bbc10]>",
    "<NSLayoutConstraint:0x72c1570 UIRoundedRectButton:0x72bbc10.baseline == UIRoundedRectButton:0x7571170.baseline>",
    "<NSLayoutConstraint:0x72c21f0 UIRoundedRectButton:0x7571170.top == UIButton:0x886efe0.top>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x72bf860 V:[UILabel:0x72bf7c0(17)]>

Break on objc_exception_throw to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
Johnny Cox
źródło
1
Ten błąd wystąpi tylko w Xcode 4.5, więc i tak nie możesz przesłać go do App Store (dopóki nie zostanie wydany)
borrrden
Czy nie ma więc nic złego? Czy byłoby możliwe użycie innej wersji xcode do przesłania do sklepu z aplikacjami?
Johnny Cox
1
Tak, coś jest nie tak, ale nie ma to znaczenia, ponieważ ma to związek z funkcją iOS, która nie jest jeszcze dostępna w publicznych wersjach Xcode. Jeśli skompiluje się z 4.4, możesz wydać go przy użyciu tej wersji (została wydana dzisiaj).
borrrden
Otrzymuję ten komunikat o błędzie dla aplikacji OS X w Xcode 4.4. Nie rozumiem tego.
Steve McLeod
@ Bartłomiej Semańczyk Czy przypadkiem mógłbyś dołączyć do pokoju: chat.stackoverflow.com/rooms/92522/autolayout-and-ios ? Przepraszamy, to przypadkowe, ale byłbym wdzięczny za twoją radę dotyczącą czegoś związanego z automatycznym układem, dzięki!
cheznead

Odpowiedzi:

275

Poleciłbym debugowanie i znalezienie ograniczenia, które jest „tym, którego nie chcesz” . Załóżmy, że masz następujący problem:

wprowadź opis obrazu tutaj

Zawsze problem polega na tym, jak znaleźć następujące ograniczenia i widoki.

Istnieją dwa rozwiązania, jak to zrobić:

  1. HIERARCHIA DEBUG VIEW (Nie polecaj tego sposobu)

Ponieważ wiesz, gdzie znaleźć nieoczekiwane ograniczenia (PBOUserWorkDayHeaderView), istnieje sposób, aby zrobić to całkiem dobrze. Znajdźmy UIViewi NSLayoutConstraintw czerwonych prostokątach. Ponieważ znamy ich identyfikator w pamięci, jest to dość łatwe.

  • Zatrzymaj aplikację przy użyciu hierarchii widoku debugowania :

wprowadź opis obrazu tutaj

  • Znajdź odpowiedni UIView:

wprowadź opis obrazu tutaj

  • Następnym krokiem jest znalezienie NSLayoutConstraint, na którym nam zależy:

wprowadź opis obrazu tutaj

Jak widać, wskaźniki pamięci są takie same. Więc wiemy, co się teraz dzieje. Dodatkowo można znaleźć NSLayoutConstraintw widoku hierarchii. Ponieważ jest zaznaczona w widoku, jest również wybierana w Nawigatorze.

wprowadź opis obrazu tutaj

Jeśli potrzebujesz, możesz również wydrukować go na konsoli za pomocą wskaźnika adresu:

(lldb) po 0x17dce920
<UIView: 0x17dce920; frame = (10 30; 300 24.5); autoresize = RM+BM; layer = <CALayer: 0x17dce9b0>>

Możesz zrobić to samo dla każdego ograniczenia, które wskaże Ci debugger :-) Teraz zdecydujesz, co z tym zrobić.

  1. DRUKUJ LEPIEJ (naprawdę polecam ten sposób, to jest Xcode 7)

    • ustaw unikalny identyfikator dla każdego ograniczenia w Twoim widoku:

wprowadź opis obrazu tutaj

  • utwórz proste rozszerzenie dla NSLayoutConstraint:

SWIFT :

extension NSLayoutConstraint {

    override public var description: String {
        let id = identifier ?? ""
        return "id: \(id), constant: \(constant)" //you may print whatever you want here
    }
}

CEL C

@interface NSLayoutConstraint (Description)

@end

@implementation NSLayoutConstraint (Description)

-(NSString *)description {
    return [NSString stringWithFormat:@"id: %@, constant: %f", self.identifier, self.constant];
}

@end
  • zbuduj go jeszcze raz, a teraz masz bardziej czytelne wyjście:

wprowadź opis obrazu tutaj

  • gdy już ją zdobędziesz, idmożesz ją po prostu dotknąć w swoim nawigatorze wyszukiwania :

wprowadź opis obrazu tutaj

  • i szybko to znajdź:

wprowadź opis obrazu tutaj

JAK PROSTO NAPRAWIĆ TĘ SPRAWĘ?

  • spróbuj zmienić priorytet na 999dla zerwanego wiązania.
Bartłomiej Semańczyk
źródło
To właśnie naprawiło mój błąd ... wielkie dzięki. Jak byś to zrobił dla celu c? Dodać kategorię?
cheznead
Dzięki za rozwiązanie, ale czy mogę użyć rozszerzenia w celu c?
dev.nikolaz
Czy ten identyfikator jest taki sam, jak accessibilityIdentifier, który jest dostępny programowo w UIViews. Jeśli nie, w jaki sposób można ustawić identyfikator programowo?
Arunabh Das
@ Nie, to nie to samo. Przeczytaj tę odpowiedź
Bartłomiej Semańczyk
3
Podoba mi się ten drugi sposób i myślę, że jest to najlepszy sposób na śledzenie zerwanego ograniczenia
Antarix
108

Problem, który masz, polega na tym, że NSAutoresizingMaskLayoutConstraints nie powinno tam być. To jest stary system sprężyn i rozpórek. Aby się go pozbyć, uruchom tę metodę w każdym widoku, który chcesz ograniczyć:

[view setTranslatesAutoresizingMaskIntoConstraints:NO];
David Wong
źródło
5
jakie są przyczyny, dla których widok w ogóle nie pojawia się po ustawieniu parametru setTranslatesAutoresizingMaskIntoConstraints na NO?
topwik
1
Jako przykład, tworzę SSBadgeView (UIView), dodaję imageView subView do SSBadgeView, a następnie dodaję SSBAdgeView jako podwidok do UIReuseableView. Dodaję pewne ograniczenia do SSBadgeView i setTranslatesAutoresizingMaskIntoConstraints: NO na SSBadgeView. obraz podrzędny SSBadgeView jest ułożony zgodnie z oczekiwaniami, ale nigdzie nie widać elementu nadrzędnego SSBadgeView obrazu.
topwik
1
Zapomniałeś wyłączyć TranslatesAutoresizingMaskIntoConstraints w swoich widokach podrzędnych
Softlion
Tak się dzieje, gdy ustawiam tę właściwość, drive.google.com/file/d/0BxuYs8WHXCF7bV9ndHFrQ0dMYVE/ ... Używam tej linii kodu: [self.contentView setTranslatesAutoresizingMaskIntoConstraints: NO]; for (widok UIView * w self.contentView.subviews) {[widok setTranslatesAutoresizingMaskIntoConstraints: NO]; } Wcześniej wyglądało to tak: drive.google.com/file/d/0BxuYs8WHXCF7OWlvZGQwN3FlbzQ/ ... Muszę przyznać, że działało.
rptwsthi
28

Uważaj , aby nie używać więcej niż jednego wiązania w tym samym kierunku i typie.

Na przykład: ograniczenie pionowości dla końcowego = 15, a drugie to> = 10.

Czasami Xcode tworzy pewne ograniczenia, których nie zauważysz . Musisz pozbyć się zbędnych ograniczeń, a ostrzeżenie dziennika na pewno zniknie.

wprowadź opis obrazu tutaj

Dodatkowo możesz odczytać i wykryć pewne przyczyny, bezpośrednio z dziennika :

NSLayoutConstraint: 0xa338390 V: | - (15) - [UILabel: 0xa331260] (Nazwy: '|': UILabel: 0xa330270)>

Możemy to odczytać jako problem w ograniczeniu UILabel, jest to wiodące ograniczenie pionowe o długości 15 punktów.

NSLayoutConstraint: 0x859ab20 H :-( 13) - | [UIView: 0x85a8fb0] ...

Byłoby to końcowe ograniczenie poziome itp.

pedrouan
źródło
6

Rzuciłem sporo tych wyjątków, najszybszym i najłatwiejszym sposobem ich rozwiązania było znalezienie unikalnych wartości w wyjątkach, których następnie szukałem w kodzie źródłowym scenorysu. Pomogło mi to znaleźć rzeczywisty widok (y) i ograniczenia (a) powodujące problem (używam znaczących userLabels na wszystkich widokach, co znacznie ułatwia śledzenie ograniczeń i widoków) ...

Tak więc, korzystając z powyższych wyjątków, otworzyłbym scenorys jako „kod źródłowy” w xcode (lub innym edytorze) i poszukałbym czegoś, co mogę znaleźć ...

<NSLayoutConstraint:0x72bf860 V:[UILabel:0x72bf7c0(17)]> 

.. to wygląda jak ograniczenie pionu (V) na UILabel o wartości (17).

Przeglądając wyjątki również znajduję

<NSLayoutConstraint:0x72c22b0 V:[UILabel:0x72bf7c0]-(NSSpace(8))-[UIButton:0x886efe0]>

Wygląda jak UILabel (0x72bf7c0) jest zbliżony do UIButton (0x886efe0) z pewnymi odstępami w pionie (8).

Miejmy nadzieję, że to wystarczy, abym znalazł określone poglądy w kodzie źródłowym scenorysu (prawdopodobnie początkowo wyszukując w tekście „17”) lub przynajmniej kilku prawdopodobnych kandydatów. Stamtąd powinienem być w stanie dowiedzieć się, które widoki są w scenorysie, co znacznie ułatwi zidentyfikowanie problemu (poszukaj „zduplikowanego” przypinania lub przypinania, które jest sprzeczne z ograniczeniami rozmiaru).

C James
źródło
„Używam znaczących userLabels” - czym są userLabels w tym kontekście? (jak je ustawić)
Stripes
W sekcji Dokument inspektora tożsamości znajduje się pole „Etykieta” .., które jest tłumaczone na wartość „userLabel” w kodzie źródłowym tablicy scenariuszy.
C James
Możesz je również ustawić, klikając wybrany widok w panelu „Przegląd” po lewej stronie (trochę jak zmiana nazwy pliku w wyszukiwarce)
C James
1
Prawdopodobnie najlepsza rzecz, jaką przeczytałem, jeśli chodzi o rozwiązanie przerażającego „Nie można jednocześnie spełnić ograniczeń”. ból. Zauważyłem, że obiekt pokazany w tym miejscu „Spróbuje odzyskać przez zerwanie ograniczenia <NSLayoutConstraint:” jest zwykle winowajcą i, jak mówi C James, prawdopodobnie jest to ograniczenie wysokości lub szerokości, które koliduje z ograniczeniami przypinania. Trudno było usunąć wysokość, ale ponieważ ograniczenia były poprawne, wysokość można było odczytać z innych ograniczeń. Dodanie ograniczenia wysokości po prostu pomieszało Auto Layout, więc właśnie tego szukam.
latenitecoder
6

Trudno mi było ustalić, jakie ograniczenia powodują ten błąd. Oto prostszy sposób na zrobienie tego.

Używam Xcode 6.1.1

  1. „Command + A”, aby wybrać wszystkie etykiety UIL, UIImages itp.
  2. Kliknij Editor -> Pin> (Select ...) to Superview
  3. ponownie kliknij Edytor -> Rozwiąż problemy z automatycznym układem -> Dodaj brakujące ograniczenia lub Resetuj do sugerowanych ograniczeń. To zależy od twojego przypadku.
Ronaldoh1
źródło
5

Miałem ten problem, ponieważ moje .xibpliki korzystały z automatycznego układu.

W inspektorze plików pierwsza zakładka. Odznaczenie opcji „Użyj automatycznego układu” rozwiązało problem.

inspektor plików autolayout

Stéphane Bruckert
źródło
Zrobiłem to i rozwiązałem problem, ale „UIImageView”, który miałem na górze ekranu (którego użyłem jako paska nawigacji), został przeniesiony na dół ekranu. Czy wiesz, dlaczego tak się stało?
dietbacon
1
Autolayout używa ograniczeń do zarządzania układem obiektów. Ponieważ właśnie wyłączyłeś autoukładanie, te ograniczenia najprawdopodobniej zniknęły, a więc pozycja twojego UIImageViewzmieniła się. Musisz ponownie ustawić tę pozycję, programowo lub za pomocą Interface Builder.
Stéphane Bruckert
5

Oto moje doświadczenie i rozwiązanie. Nie dotknąłem kodu

  1. Wybierz widok (UILabel, UIImage itp.)
  2. Edytor> Przypnij> (Wybierz ...) do nadzoru
  3. Edytor> Rozwiąż problemy z automatycznym układem> Dodaj brakujące ograniczenia
royemi
źródło
4

użyj szybko tego kodu

view.translatesAutoresizingMaskIntoConstraints = false
Arun Kumar P.
źródło
1
To szybka odpowiedź na pytanie oznaczone tagiem „c”.
Tobi Nary
2
@SmokeDispenser W każdym razie wspomniałem, że jest to szybki kod. i to działa dla mnie. szybki / obiektywny to ma wspólny SDK dotykowy kakao.
Arun Kumar P
2

Śledziłem pytania i odpowiedzi SO z każdego zapytania wyszukiwania. Ale wszystkie są powiązane z konkretnym.

Zasadniczo mam na myśli, że zanim zapiszesz format (może być prosty), wyświetli ostrzeżenia.

Od iOS 8.0 domyślnie widoki są klasami wielkości. Nawet jeśli wyłączysz klasy rozmiarów, nadal będzie zawierał pewne ograniczenia dotyczące automatycznego układu.

Więc jeśli planujesz ustawić ograniczenia za pomocą kodu używającego VFL. Następnie musisz zająć się jedną z poniższych linii.

// Remove constraints if any.
[self.view removeConstraints:self.view.constraints];

Dużo szukałem w SO, ale rozwiązanie leżało w Apple Sample Code .

Dlatego musisz usunąć domyślne ograniczenia przed planowaniem dodania nowego.

Kampai
źródło
1

Dla mnie głównym powodem tego problemu było to, że zapomniałem odznaczyć AutoLayoutw Xibedytorze. W rzeczywistości zrobiłem wiele poprawek XIBw kodzie.

giuseppe
źródło
1
 for(UIView *view in [self.view subviews]) {
    [view setTranslatesAutoresizingMaskIntoConstraints:NO];
}

Pomogło mi to uchwycić widok powodujący problem.

Grant Carlisle
źródło
1

Żadna z powyższych odpowiedzi nie jest pomocna w mojej sytuacji. Używam XCode 10.1 i testuję moją aplikację na symulatorze pod kątem „iPada (5. generacji)”. Symulator działa pod kontrolą systemu iOS 12.1.

Mam prosty widok główny w mojej planszy, z dwoma widokami podrzędnymi UITextField. W scenorysie nie ma żadnych ograniczeń. I nie mam obiektów UIButtonBarView w aplikacji ani w scenorysie.

Żadne wiadomości nie są drukowane po uruchomieniu aplikacji i przedstawia widok główny. Brak, gdy symulowane urządzenie jest obracane.

Ale w symulatorze w momencie, gdy kliknę na jedno z pól tekstowych, rozszerzenie klawiatury wyłania się z dołu ekranu, chociaż nie jest to pełna klawiatura, która nigdy nie pojawia się w symulatorze. Ale na terminalu jest drukowany:

Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want. 
Try this: 
    (1) look at each constraint and try to figure out which you don't expect; 
    (2) find the code that added the unwanted constraint or constraints and fix it. 
(Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
"<NSAutoresizingMaskLayoutConstraint:0x6000034e7700 h=--& v=--& UIKeyboardAssistantBar:0x7f9c7d714af0.height == 0   (active)>",
"<NSLayoutConstraint:0x6000034aba20 V:|-(0)-[_UIUCBKBSelectionBackground:0x7f9c7d51ec70]   (active, names: '|':_UIButtonBarButton:0x7f9c7d51de40 )>",
"<NSLayoutConstraint:0x6000034aba70 _UIUCBKBSelectionBackground:0x7f9c7d51ec70.bottom == _UIButtonBarButton:0x7f9c7d51de40.bottom   (active)>",
"<NSLayoutConstraint:0x6000034fb3e0 V:|-(0)-[_UIButtonBarStackView:0x7f9c7d715880]   (active, names: '|':UIKeyboardAssistantBar:0x7f9c7d714af0 )>",
"<NSLayoutConstraint:0x6000034fb750 V:[_UIButtonBarStackView:0x7f9c7d715880]-(0)-|   (active, names: '|':UIKeyboardAssistantBar:0x7f9c7d714af0 )>",
"<NSLayoutConstraint:0x6000034abc00 'UIButtonBar.maximumAlignmentSize' _UIButtonBarButton:0x7f9c7d51de40.height == UILayoutGuide:0x600002ef4e00'UIViewLayoutMarginsGuide'.height   (active)>",
"<NSLayoutConstraint:0x6000034d7cf0 'UIView-bottomMargin-guide-constraint' V:[UILayoutGuide:0x600002ef4e00'UIViewLayoutMarginsGuide']-(9)-|   (active, names: '|':_UIButtonBarStackView:0x7f9c7d715880 )>",
"<NSLayoutConstraint:0x6000034d7c50 'UIView-topMargin-guide-constraint' V:|-(10)-[UILayoutGuide:0x600002ef4e00'UIViewLayoutMarginsGuide']   (active, names: '|':_UIButtonBarStackView:0x7f9c7d715880 )>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x6000034aba70 _UIUCBKBSelectionBackground:0x7f9c7d51ec70.bottom == _UIButtonBarButton:0x7f9c7d51de40.bottom   (active)>

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

Z pewnością wydaje mi się, że wszystko to nie ma nic wspólnego z moją aplikacją, a wszystko ma związek z tym, jak Apple tworzy własny widok klawiatury, nawet z moim małym rozszerzeniem zadeklarowanym jako z nim połączone.

Pozostaje więc pytanie, czy jest coś, za co jestem odpowiedzialny jako programista aplikacji (zakładając, że jest to kilka rzeczy, którymi warto się zająć), czy jest to tylko problem / błąd Apple?

FWIW, ten komunikat o problemie z ograniczeniami nie pojawia się podczas symulacji nowszego modelu iPada, takiego jak iPad Pro 12,9 cala (3. generacji). Ale komunikat pojawia się podczas symulacji iPada Pro 9,7 cala ”. Wszyscy twierdzą, że mają system iOS 12.1.

jsbox
źródło
1

Otrzymuję ten sam błąd, ale tylko w określonym widoku, kiedy dotykam pierwszego pola tekstowego, a następnie następnego pola tekstowego w dół.

Piszę w SwiftUI na iOS 13.4

 Unable to simultaneously satisfy constraints.
        Probably at least one of the constraints in the following list is one you don't want. 
        Try this: 
            (1) look at each constraint and try to figure out which you don't expect; 
            (2) find the code that added the unwanted constraint or constraints and fix it. 
    (
        "<NSLayoutConstraint:0x2809b6760 'assistantHeight' TUISystemInputAssistantView:0x105710da0.height == 44   (active)>",
        "<NSLayoutConstraint:0x2809ccff0 'assistantView.bottom' TUISystemInputAssistantView:0x105710da0.bottom == _UIKBCompatInputView:0x10525ae10.top   (active)>",
        "<NSLayoutConstraint:0x2809cccd0 'assistantView.top' V:|-(0)-[TUISystemInputAssistantView:0x105710da0]   (active, names: '|':UIInputSetHostView:0x105215010 )>",
        "<NSLayoutConstraint:0x2809ca300 'inputView.top' V:|-(0)-[_UIKBCompatInputView:0x10525ae10]   (active, names: '|':UIInputSetHostView:0x105215010 )>"
    )

    Will attempt to recover by breaking constraint 
    <NSLayoutConstraint:0x2809ccff0 'assistantView.bottom' TUISystemInputAssistantView:0x105710da0.bottom == _UIKBCompatInputView:0x10525ae10.top   (active)>

    Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
    The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKitCore/UIView.h> may also be helpful.
DckBrd
źródło
0

Otrzymywałem również ten sam problem z łamaniem ograniczeń w dzienniku, dla ViewCircle w xib. Prawie wypróbowałem wszystko wymienione powyżej i nic nie działało. Następnie próbowałem zmienić priorytet ograniczenia wysokości, które łamało się w dzienniku (potwierdzone przez dodanie identyfikatorów ograniczeń na xib) tutaj wpisz opis zdjęcia

Mogołów
źródło
-1

Jedną rzeczą, na którą trzeba uważać (przynajmniej to mnie zaskoczyło) było to, że usuwałem ograniczenie ze złego widoku. Ograniczenie, które próbowałem usunąć, nie było dziecięcym ograniczeniem mojego widzenia, więc kiedy to zrobiłem

myView.removeConstraint(theConstraint)

w rzeczywistości niczego nie usuwałam, bo musiałam zadzwonić

myView.superView.removeConstraint(theConstraint)

ponieważ ograniczenie było technicznie ograniczeniem rodzeństwa mojego punktu widzenia.

Adam Johns
źródło
-4

szybki 4

Po prostu dodaję tę linię w viewDidLoad i dobrze ze mną współpracuje.

view.removeConstraints(view.constraints)
Faris
źródło