【问题标题】:'NSInvalidArgumentException', reason: 'Unable to parse constraint format''NSInvalidArgumentException',原因:'无法解析约束格式'
【发布时间】:2012-10-14 06:06:56
【问题描述】:

我有一个子视图,我想在旋转屏幕期间保持停止,所以我决定放置 NSLayoutConstraint 类型:

到 Superview 的尾随空间
顶部空间到 Superview
到 Superview 的按钮空间
我在 UITableViewCell 的子类中。我编写了代码,但出现以下错误:

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


我在 CustomCell.m 中的代码是:

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

【问题讨论】:

    标签: ios layout compiler-errors constraints autolayout


    【解决方案1】:

    看起来自动布局可视化格式解析引擎将 VFL 约束中的“.”解释为 keyPath,而不是像使用 valueForKeyPath: 那样的键。

    NSDictionaryOfVariableBindings(...) 将采用括号中的任何参数并将其转换为以对象为值的文字键(在您的情况下为:@{"self.arrow" : self.arrow})。对于 VFL,自动布局认为您的视图字典中有一个名为 self 的键,其子字典(或子对象)的键为 arrow

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

    当您确实希望系统将您的密钥解释为“self.arrow”时。

    通常,当我像这样使用实例变量 getter 时,我通常最终会创建自己的字典,而不是像这样使用 NSDictionaryOfVariableBindings(...)

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

    NSDictionary *views = NSDictionaryOfVariableBindings(_arrow);
    

    这将允许您在没有 self 的情况下使用 VFL 中的视图,并且您仍然知道自己在说什么:

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

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

    作为一般规则,我已经学会了不要在其中包含带点 (.) 的字典键,以避免任何系统混乱或调试噩梦。

    【讨论】:

    • 文档给出了使用 NSDictionaryOfVariableBindings 创建字典的示例,这很荒谬,但不要提到它不适用于任何属性或 IBOutlets
    • 乔纳森,我自己也很困惑。文档特别声明使用该方法。我只是认为删除自我足够聪明。部分键自动。
    • “相当荒谬”是……本周的轻描淡写。
    【解决方案2】:

    我的诀窍是简单地声明一个局部变量,它只是另一个指向属性的指针,并将它放在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);
    

    P 后缀用于“指针”。

    【讨论】:

    • 这否定了 NSDictionaryOfVariableBindings 的意义,就是让事情变得更短。为什么不改用NSDictionary *views = @{@"myButton":self.myButton, @"myLabel":self.myLabel}?它更短。
    • 如果您有很长的其他视图列表并且想要插入对self.view 的引用,它根本不会否定这一点。
    • 为什么要这样做而不是使用 _myButton 和 _myLabel?或综合以不同的方式命名 ivars?
    • 因为你可能不想仅仅为了这个问题而改变你的编码风格。
    【解决方案3】:

    最简单的解决方案是避免从您自己的类中获取变量,并将超类中的变量重新定义为局部变量。您的示例的解决方案是

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

    【讨论】:

      【解决方案4】:

      确保在将所需的子视图添加到主视图后添加约束。需要一段时间才能了解与此问题相关的知识。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多