J'ai une sous-vue que je souhaite conserver lors de la rotation de l'écran, j'ai donc décidé de mettre le type NSLayoutConstraint:
Trailing Space to Superview
Top Space to Superview
Espace des boutons vers Superview
Je fais partie d'une sous-classe de UITableViewCell. J'ai écrit le code mais j'obtiens l'erreur suivante:
'NSInvalidArgumentException', reason: 'Unable to parse constraint format:
self is not a key in the views dictionary.
H:[self.arrows]-5-|
Mon code dans CustomCell.m est:
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];
Il semble que le moteur d'analyse au format visuel de la mise en page automatique interprète le ".
" Dans votre contrainte VFL comme étant un chemin de clé au lieu d'une clé comme celle qui utilise valueForKeyPath:
.
NSDictionaryOfVariableBindings(...)
prendra tout ce que votre paramètre est entre parenthèses et le traduira en une clé littérale avec l'objet comme valeur (dans votre cas: @{"self.arrow" : self.arrow}
). Dans le cas du VFL, la mise en page automatique pense que vous avez une clé nommée self
dans votre dictionnaire de vues avec un sous-domaine (ou sous-objet) qui a une clé de arrow
,
@{
@"self" : @{ @"arrow" : self.arrow }
}
lorsque vous vouliez littéralement que le système interprète votre clé comme "self.arrow
".
Habituellement, lorsque j'utilise un getter de variables d'instance comme celui-ci, je finis généralement par créer mon propre dictionnaire au lieu d'utiliser NSDictionaryOfVariableBindings(...)
comme ceci:
NSDictionary *views = @{ @"arrowView" : self.arrow }
ou
NSDictionary *views = NSDictionaryOfVariableBindings(_arrow);
Ce qui vous permettrait d'utiliser la vue dans votre VFL sans vous-même et vous savez toujours de quoi vous parlez:
NSArray *arrowHorizConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:[arrowView]-5-|" options:0 metrics:nil views];
ou
NSArray *arrowHorizConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:[_arrow]-5-|" options:0 metrics:nil views];
En règle générale, j'ai appris à ne pas avoir de clés de dictionnaire avec un point (.
) Pour éviter toute confusion système ou déboguer des cauchemars.
Mon astuce consiste à simplement déclarer une variable locale qui n'est qu'un autre pointeur vers la propriété et à la placer dans le 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);
Le suffixe P
est pour "pointeur".
La solution la plus simple consiste à éviter les getters pour les variables de votre propre classe et à redéfinir les variables des superclasses en tant que variables locales. Une solution pour votre exemple est
UIView *contentView = self.contentView;
NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(_arrows, contentView);