2013-05-02 5 views
7

Apprezzo che XCode catturi l'inviolabile NSLayoutConstraints e ti fornisca alcune informazioni a riguardo, tuttavia non so come prendere gli indirizzi di memoria dei controlli/vincoli e mapparli al controlli effettivi che hanno problemi.Mappatura dell'indirizzo di memoria di NSLayoutConstraints non soddisfacente ai controlli dell'interfaccia utente

La mia app è abbastanza grande (circa 20 schermi), alcuni sono grandi UIViewControllers con diversi controller di visualizzazione figlio al loro interno. Alcuni sono UITableViews con celle personalizzate e UICollectionViews con celle personalizzate. Sto avendo un sacco di tempo virate verso il basso la causa di questo errore (che avviene a rotazione orizzontale)

Ecco le informazioni dalla mia console:

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. 

Come si può vedere, ci sono la memoria indirizzi elencati. Incollare quelli nella barra di ricerca della finestra di controllo non rivela molto. Inoltre, spulciando gli stack delle chiamate thread e code, ottengo solo codice disassemblato su questo breakpoint (punto di interruzione delle eccezioni).

risposta

0

Si potrebbe provare a utilizzare visualizeConstraints:, come indicato here, e vedere se è possibile trovare i vincoli cattivi in ​​questo modo.

+0

visualizeConstraints funziona solo su OS X –

+0

Whoops! Per qualche ragione, ho pensato che UILayoutConstraint fosse una cosa, e quindi ho pensato che fosse sul Mac. Immagino di non aver letto abbastanza attentamente la domanda! –

4

La risposta breve non è realmente, OS X ha una proprietà identificatore che può essere impostata su una vista che viene utilizzata da NSLayoutConstraint per aiutare a identificare le viste ma che non esiste ancora su iOS.

Tuttavia, c'è un "work around" per implementare qualcosa di simile su iOS ma non è bello. Per prima cosa devi stabilire un nome per ogni vista, questo è ottenuto nella categoria UIView. Quindi è necessario aggiornare l'output per la descrizione NSLayoutConstraint per utilizzare i nuovi tag.

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

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

quindi fornire l'implementazione come modificare l'uscita di 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 

Allora si sarà in grado di impostare i nomi sui vostri punti di vista in questo modo

self.view.nametag = @"MyUsefulName"; 

O definirli in IB

nametag in IB

Infine, quando si eliminano i vincoli, si ottengono i nomi forniti nell'output.

"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), " 

Si dovrebbe utilizzare questo codice nel tuo build di debug, non spedirlo in un app perché accede al metodo privato [NSLayoutConstraint asciiArtDescription].

+0

Tecnica interessante. Questo potrebbe essere davvero utile se lo conosci sin dall'inizio e rendilo parte della tua routine di implementazione standard. Sospetto alcuni controlli, quindi applicherò questa tecnica e vedrò cosa succede. – VaporwareWolf

+0

Questo è davvero un approccio interessante. Un'utile aggiunta è semplicemente usare la proprietà 'accessibilityLabel' esistente su' UIView' piuttosto che crearne una nuova. Dovresti comunque compilare la proprietà 'accessibilityLabel'. :) –

+0

Questo metodo è spiegato anche in http://www.objc.io/issue-3/advanced-auto-layout-toolbox.html, sezione Debug – giampaolo

6

Ho trovato una specie di soluzione grazie a questi siti Web: Debugging iOS AutoLayout Issues e Dancing with the Debugger. Grazie alla console Xcode, puoi identificare da quale vista proviene il problema.

La soluzione:

  • Fase 1:

    • Aprire il punto di interruzione Navigator (cmd + 7)
    • Fare clic sul pulsante 'Aggiungi' in basso a sinistra
    • Selezionare ' Aggiungi punto di interruzione simbolico '
    • Dove si dice' Simbolo 'digitare UIViewAlertForUnsatisfiableConstraints
  • Passaggio 2: Esegui il tuo progetto. Quando la console stampa Will attempt to recover by breaking constraint <NSLayoutConstraint:0x7fc82d3e18a0 H:[UIView:0x7fc82aba1210(768)]>, copiare l'indirizzo di memoria della vista (0x7fc82aba1210 qui).

  • Fase 3: Modificare lo sfondo di questa vista per sapere quale è con questo comando nella console: e (void)[0x7fc82d3e18a0 setBackgroundColor:[UIColor redColor]]

  • Fase 4: Continuare il programma e vedere l'interfaccia utente aggiornata. La vista con il colore di sfondo rosso è la vista in questione.

  • Passaggio 5: torna al tuo IB e trova il vincolo su questa vista.

+1

Fase 3 è stato grande! –