2012-10-24 15 views
50

mam subview że chcę zachować przystanków podczas ekran obraca się, więc postanowiłem umieścić typ NSLayoutConstraint:

Trailing Space Superview
górę Space to Superview
Przestrzeń przycisków do Superview
Jestem w podklasie UITableViewCell. Napisałem kod, ale pojawia się następujący błąd:
„NSInvalidArgumentException”, powód: „Nie można przeanalizować formatu ograniczeń”

'NSInvalidArgumentException', reason: 'Unable to parse constraint format: 
self is not a key in the views dictionary. 
H:[self.arrows]-5-| 


Mój kod w CustomCell.m jest:

self.arrows = [[Arrows alloc]initWithFrame:CGRectMake(self.contentView.bounds.size.width-30, self.bounds.origin.y+4, 30, self.contentView.bounds.size.height-4)]; 

NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(self.arrows, self.contentView); 
NSMutableArray * constraint=[[NSMutableArray alloc]init]; 
[constraint addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H: [self.arrows]-5-|" options:0 metrics:nil views:viewsDictionary]]; 
[constraint addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-1-[self.arrows]" options:0 metrics:nil views:viewsDictionary]]; 
[constraint addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"[V: [self.arrows]-1-|" options:0 metrics:nil views:viewsDictionary]]; 
[self.arrows addConstraints:constraint]; 

Odpowiedz

121

Wygląda na to, że silnik autolayout Format wizualny parsowania jest interpretowanie "." w twoim ograniczeniu VFL jest kluczem keyPath zamiast kluczem podobnym do tego, który używa valueForKeyPath:.

NSDictionaryOfVariableBindings(...) zajmie cokolwiek jest twoim parametrem w nawiasie i przetłumaczy go na literalny klucz z obiektem jako wartością (w twoim przypadku: @{"self.arrow" : self.arrow}). W przypadku VFL, autolayout myśli, że masz klucz o nazwie self w słowniku widok z subdictionary (lub podobiektu), który ma klucz arrow,

@{ 
    @"self" : @{ @"arrow" : self.arrow } 
} 

kiedy dosłownie chciał system do interpretowania Twój klucz jako "self.arrow".

Zazwyczaj, gdy używam instancji zmienne Getter tak, to zazwyczaj kończy się tworząc własną słownika zamiast korzystania NSDictionaryOfVariableBindings(...) tak:

NSDictionary *views = @{ @"arrowView" : self.arrow } 

lub

NSDictionary *views = NSDictionaryOfVariableBindings(_arrow); 

które pozwala ci używać widoku w twoim VFL bez własnego ja i wciąż wiesz, o czym mówisz:

NSArray *arrowHorizConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:[arrowView]-5-|" options:0 metrics:nil views]; 

lub

NSArray *arrowHorizConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:[_arrow]-5-|" options:0 metrics:nil views]; 

Zgodnie z ogólną zasadą, nauczyłem się nie mieć słownika klucze z kropką (.) w nich, aby uniknąć nieporozumień systemu lub koszmary debugowania.

+1

Dziękuję bardzo –

+25

Dość śmieszne, że docs podać przykłady z użyciem 'NSDictionaryOfVariableBindings' do tworzenia słownika, ale nie wspomnieć, że nie będzie działać z każdą własność lub IBOutlets –

+0

Jonathan, sam byłem tym trochę zdezorientowany. Dokumenty wyraźnie stwierdzają, że używają tej metody. Po prostu pomyślałem, że to wystarczająco inteligentne, by usunąć siebie. część klucza automatycznie. – Nailer

7

Moją sztuczką jest po prostu zadeklarowanie zmiennej lokalnej, która jest tylko kolejnym wskaźnikiem do właściwości, i umieszczenie jej w NSDictionaryOfVariableBindings.

@interface ViewController() 
@property (strong) UIButton *myButton; 
@property (strong) UILabel *myLabel; 
@end 

... 

UIButton *myButtonP = self.myButton; 
UILabel *theLabelP = self.myLabel; 
NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(myButtonP, myLabelP); 

Sufiks P dotyczy "wskaźnika".

+2

To neguje punkt NSDictionaryOfVariableBindings, który ma na celu skrócenie czasu. Dlaczego nie używać 'NSDictionary * views = @ {@" myButton ": self.myButton, @" myLabel ": self.myLabel}' zamiast? Jest krótszy. –

+0

Nie neguje to w ogóle, jeśli masz długą listę innych widoków i chcesz wstawić odwołanie do 'self.view'. – davidf2281

+0

dlaczego to zrobić zamiast używać _mojButton i _myLabel? lub syntezować, aby nazwać ivars w inny sposób? –

-1

Pamiętaj, aby dodać ograniczenia po dodaniu wymaganego widoku podrzędnego do widoku głównego. Pobranie wiedzy związanej z tym problemem zajęło trochę czasu.

1

Najprostszym rozwiązaniem jest uniknięcie modułów pobierających dla zmiennych z własnej klasy i ponowne zdefiniowanie zmiennych z nadklas jako zmiennych lokalnych.Rozwiązanie dla przykładu jest

UIView *contentView = self.contentView; 
NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(_arrows, contentView); 
Powiązane problemy