2013-05-02 11 views
7

Doceniam, że XCode złapie niezatłumialne NSLayoutConstraints i poda pewne informacje na ten temat, jednak nie wiem, jak wziąć adresy pamięci kontrolek/wiązań i mapować je do rzeczywiste kontrole, które mają problem.Odwzorowywanie adresów niewystarczających ograniczeń NSLayoutConstraint na elementy sterujące interfejsu użytkownika

Moja aplikacja jest dość duża (około 20 ekranów), niektóre z nich są dużymi kontrolerami UIViewController z kilkoma kontrolerami widoku dziecka. Niektóre są UITableViews z niestandardowymi komórkami i UICollectionViews z niestandardowymi komórkami. Mam piekło czasu sklejaniu dół przyczynę tego błędu (co zdarza się na rotacji poziomej)

Oto informacja z mojego konsoli:

2013-05-02 11:18:53.225 Smile[7519:c07] 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:0x16083b60 h=-&- v=-&- UIView:0xa5a1d00.width == UIWindow:0xa09eee0.width>", 
    "<NSLayoutConstraint:0xa5a2180 V:[UIView:0xa59f160]-(954)-| (Names: '|':UIView:0xa5a1d00)>", 
    "<NSLayoutConstraint:0xa5a2140 V:|-(0)-[UIView:0xa59f160] (Names: '|':UIView:0xa5a1d00)>", 
    "<NSAutoresizingMaskLayoutConstraint:0xa593340 h=--- v=--- H:[UIWindow:0xa09eee0(768)]>" 
) 

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0xa5a2180 V:[UIView:0xa59f160]-(954)-| (Names: '|':UIView:0xa5a1d00)> 

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. 

Jak widać, istnieje pamięć wymienione adresy. Wklejenie tych elementów w pasku wyszukiwania okna zegarka niewiele się odsłania. Przeszukując wątki i stosy wywołań w kolejce, otrzymuję tylko zdemontowany kod w tym punkcie przerwania (punkt przerwania wyjątków).

Odpowiedz

0

Możesz spróbować użyć polecenia visualizeConstraints:, jak wspomniano pod nr here, i sprawdzić, czy można znaleźć złe ograniczenia w ten sposób.

+0

wizualizacjaConstraints działa tylko na OS X –

+0

Whoops! Z jakiegoś powodu myślałem, że UILayoutConstraint to coś, dlatego pomyślałem, że to na Macu. Sądzę, że nie przeczytałem dokładnie tego pytania! –

4

Krótka odpowiedź tak naprawdę nie jest, OS X ma właściwość identyfikatora, która może być ustawiona w widoku używanym przez NSLayoutConstraint do pomocy w identyfikowaniu widoków, ale to jeszcze nie istnieje na iOS.

Jednak istnieje "praca dookoła", aby zaimplementować coś podobnego na iOS, ale nie jest ładna. Najpierw musisz ustalić nazwę dla każdego widoku, co zostało wykonane w kategorii UIView. Następnie musisz zaktualizować dane wyjściowe opisu NSLayoutConstraint, aby użyć nowych tagów.

@interface NSLayoutConstraint (Nametags) 
- (NSString *)asciiArtDescription; 
@end 

@interface UIView (Nametags) 
@property (nonatomic, strong) NSString *nametag; 
@end 

Następnie zapewnić realizację w następujący sposób, aby zmienić wyjście NSLayout

#import <objc/objc-runtime.h> 

static const char nametag_key; 
@implementation NSLayoutConstraint (Nametags) 

- (NSString *)description { 
    NSMutableString *myDescription = [NSMutableString stringWithFormat:@"%@, ", [self asciiArtDescription]]; 
    UIView *firstView = (UIView *)[self firstItem]; 
    if (firstView) { 
     [myDescription appendFormat:@"First View: 0x%0x: %@, ", (int)firstView, firstView.nametag]; 
    } 

    UIView *secondView = (UIView *)[self secondItem]; 
    if (secondView) { 
     [myDescription appendFormat:@"Second View: 0x%0x: %@", (int)secondView, secondView.nametag]; 
    } 

    return myDescription; 
} 
@end 

@implementation UIView (Nametags) 
- (id) nametag { 
    return objc_getAssociatedObject(self, (void *) &nametag_key); 
} 

- (void)setNametag:(NSString *) theNametag { 
    objc_setAssociatedObject(self, (void *) &nametag_key, theNametag, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 
} 
@end 

wtedy będzie w stanie ustalić nazwiska na swoich poglądów jak tak

self.view.nametag = @"MyUsefulName"; 

lub zdefiniować je w IB

nametag in IB

W końcu, gdy kiedykolwiek zrzucisz wiązania, otrzymasz nazwy podane w danych wyjściowych.

"V:|-(202)-[UIView:0x75606f0], First View: 0x75606f0: Blue View, Second View: 0x7560bd0: (null)", 
"V:[UIView:0x75606f0]-(72)-|, First View: 0x7560bd0: (null), Second View: 0x75606f0: Blue View", 
"V:[UIView:0x7560bd0(548)], First View: 0x7560bd0: (null), " 

Należy używać tylko ten kod na swoją debugowania buduje, nie wysłać go w aplikacji, ponieważ dostęp do prywatnej [NSLayoutConstraint asciiArtDescription] metody.

+0

Ciekawa technika. Może to być przydatne, jeśli wiesz o tym od samego początku i sprawisz, że stanie się częścią standardowej procedury implementacji. Podejrzewam kilka kontroli, więc zastosuję tę technikę i zobaczę, co się stanie. – VaporwareWolf

+0

To naprawdę ciekawe podejście. Przydatnym dodatkiem jest użycie istniejącej właściwości 'accessibilityLabel' na' UIView' zamiast utworzenia nowej właściwości. W każdym razie powinieneś wypełniać właściwość 'accessibilityLabel'. :) –

+0

Ta metoda jest wyjaśniona również w http://www.objc.io/issue-3/advanced-auto-layout-toolbox.html, w sekcji Debugowanie – giampaolo

6

Znalazłem rodzaj rozwiązania dzięki tym stronom internetowym: Debugging iOS AutoLayout Issues i Dancing with the Debugger. Dzięki konsoli Xcode możesz określić, z którego widoku pochodzi problem.

Rozwiązanie:

  • Krok 1:

    • Otwórz Breakpoint Navigator (Cmd + 7)
    • kliknij 'Dodaj' przycisk w lewym dolnym
    • Wybierz ' Dodaj symboliczny punkt przerwania "
    • Gdzie jest napisane" Symbol "w UIViewAlertForUnsatisfiableConstraints
  • Krok 2: Uruchom swój projekt. Gdy konsola wypisze Will attempt to recover by breaking constraint <NSLayoutConstraint:0x7fc82d3e18a0 H:[UIView:0x7fc82aba1210(768)]>, skopiuj adres pamięci widoku (tutaj: 0x7fc82aba1210).

  • Krok 3: Zmień tle tego widoku wiedzieć, który z nich jest z tego polecenia w konsoli: e (void)[0x7fc82d3e18a0 setBackgroundColor:[UIColor redColor]]

  • Krok 4: Kontynuować program i zobaczyć zaktualizowaną UI. Widok z czerwonym kolorem tła to widok, o którym mowa.

  • Krok 5: Wróć do swojego IB i sprawdź, które ograniczenie jest problemem w tym widoku.

+1

Krok 3 był świetny! –