topanchor programmatic constraint code ios layout compiler-errors constraints autolayout

ios - code - programmatically constraints swift 4



''NSInvalidArgumentException'', razón: ''No se puede analizar el formato de restricción'' (4)

Asegúrese de agregar las restricciones después de agregar la subvista requerida a su vista principal. Tomó un tiempo obtener conocimiento relacionado con este problema.

Tengo una subvista que quiero mantener se detiene durante la rotación de pantalla, así que decidí poner el tipo NSLayoutConstraint:

Trailing Space para Superview
Top Space para Superview
Espacio de botones para Superview
Estoy en una subclase de UITableViewCell. Escribí el código pero me aparece el siguiente error:

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


Mi código en CustomCell.m es:

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];


La solución más fácil es evitar los captadores de las variables de su propia clase y redefinir las variables de las superclases como variables locales. Una solución para su ejemplo es

UIView *contentView = self.contentView; NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(_arrows, contentView);


Mi truco es simplemente declarar una variable local que sea simplemente otro puntero a la propiedad, y ponerla en 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);

El sufijo P es para "puntero".


Parece que el motor de análisis de formato visual de autolayout interpreta el " . " En su restricción VFL para ser un KeyPath en lugar de una clave como si valueForKeyPath: usando valueForKeyPath:

NSDictionaryOfVariableBindings(...) tomará cualquier parámetro que esté entre paréntesis y lo traducirá en una clave literal con el objeto como valor (en su caso: @{"self.arrow" : self.arrow} ). En el caso del VFL, autolayout está pensando que tiene una clave llamada self en su diccionario de vista con un subdiccionario (o subobjeto) que tiene una tecla de arrow ,

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

cuando, literalmente, quería que el sistema interpretara su clave como " self.arrow ".

Por lo general, cuando estoy usando un getter de variables de instancia como este, normalmente termino creando mi propio diccionario en lugar de usar NSDictionaryOfVariableBindings(...) como sigue:

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

o

NSDictionary *views = NSDictionaryOfVariableBindings(_arrow);

Lo cual te permitiría usar la vista en tu VFL sin ti mismo y aún sabes de lo que estás hablando:

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

o

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

Como regla general, aprendí a no tener claves de diccionario con un punto ( . ) En ellas para evitar confusiones en el sistema o pesadillas de depuración.