首先作个简单的小实验,在storyboard拖放一个view,添加好约束。以后利用masonry分别去更新这个视图的位置,尺寸。会发现不同的结果。bash
//更新尺寸
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[super touchesBegan:touches withEvent:event];
[self.viewTest mas_updateConstraints:^(MASConstraintMaker *make) {
//和storyboard中的约束相同
make.width.mas_equalTo(375.0);
}];
}
//更新位置
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[super touchesBegan:touches withEvent:event];
[self.viewTest mas_updateConstraints:^(MASConstraintMaker *make) {
//和storyboard中的约束相同
make.left.equalTo(self.viewTest.superview);
}];
}
复制代码
若是你这么作会惊奇的发现更新位置有效,更新尺寸无效。why?到底用masonry能不能更新xib上的约束?带着这个问题咱们去深刻探索。布局
其实上面两个小实验控制台都有打印警告 ui
那说明mas_updateConstraints致使多出来一个约束致使了约束冲突。让咱们看看源代码。spa
//调用代码
- (NSArray *)mas_updateConstraints:(void(^)(MASConstraintMaker *))block {
self.translatesAutoresizingMaskIntoConstraints = NO;
MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];
//更新存在的约束
constraintMaker.updateExisting = YES;
block(constraintMaker);
return [constraintMaker install];
}
//最终要执行的代码
- (void)install {
if (self.hasBeenInstalled) {
return;
}
.......
MASLayoutConstraint *existingConstraint = nil;
//判断是否更新存在约束(刚刚这里赋值了YES)
if (self.updateExisting) {
//下边去当前view上的约束里去匹配传过来的约束,若是相同返回这个约束,不然nil
existingConstraint = [self layoutConstraintSimilarTo:layoutConstraint];
}
//找到了匹配的约束
if (existingConstraint) {
// just update the constant
//更新约束的值
existingConstraint.constant = layoutConstraint.constant;
self.layoutConstraint = existingConstraint;
} else {
//没找到匹配约束就在当前view上添加外边传过来的约束
[self.installedView addConstraint:layoutConstraint];
self.layoutConstraint = layoutConstraint;
[firstLayoutItem.mas_installedConstraints addObject:self];
}
}
//遍历匹配当前view上的约束
- (MASLayoutConstraint *)layoutConstraintSimilarTo:(MASLayoutConstraint *)layoutConstraint {
// check if any constraints are the same apart from the only mutable property constant
// go through constraints in reverse as we do not want to match auto-resizing or interface builder constraints
// and they are likely to be added first.
/** 大体意思是倒序遍历查找约束,过滤掉了auto-resizing,interface builder 上的约束,也就是说遍历时候不考虑xib上的约束这样碰到xib上的约束后就直接continue了,最终会找不到匹配的约束返回nil */
for (NSLayoutConstraint *existingConstraint in self.installedView.constraints.reverseObjectEnumerator) {
if (![existingConstraint isKindOfClass:MASLayoutConstraint.class]) continue;
if (existingConstraint.firstItem != layoutConstraint.firstItem) continue;
if (existingConstraint.secondItem != layoutConstraint.secondItem) continue;
if (existingConstraint.firstAttribute != layoutConstraint.firstAttribute) continue;
if (existingConstraint.secondAttribute != layoutConstraint.secondAttribute) continue;
if (existingConstraint.relation != layoutConstraint.relation) continue;
if (existingConstraint.multiplier != layoutConstraint.multiplier) continue;
if (existingConstraint.priority != layoutConstraint.priority) continue;
return (id)existingConstraint;
}
return nil;
}
复制代码
经过上面分析咱们知道了,xib上的约束是不去匹配的最终existingConstraint被赋值了nil。致使最终执行了[self.installedView addConstraint:layoutConstraint];新加了一个约束。而这个新的约束每每是最高优先级的,而且xib上的约束发现默认也是最高优先级因此致使了约束冲突。控制台打印了警报。code
步骤一分析得出的结论是mas_updateConstraints方法致使新增了一个同优先级的约束致使了约束冲突。那咱们尝试去改一下xib上的相应约束的优先级,调低些。在运行代码发现控制台并无报错输出,同时不管更新尺寸仍是位置都有效。这也进一步验证了步骤一的结论。cdn
经过以上分析得出,masonry不能直接更新xib上的约束。若是咱们用mas_updateConstraints方法,masonry会新增一个约束,有可能会致使约束冲突,控制台打印警报,视图布局错乱。blog
那怎么去更新xib上的约束的。有两个方案,一是脱出来约束直接修改值。二是改变xib上的对应约束优先级,把优先级调低。而后用masonry去添加更高优先级的约束便可。相比较而言以为方式一更好些。由于更改优先级其实就是要废掉xib上的约束,不够直接麻烦。图片
一开始的两个小实验,由于masonry不能直接更新xib上的约束,致使mas_updateConstraints方法其实是新增了一个最高优先级的约束,致使约束冲突,控制台打印警报。这能够解释通。ip
可是为何一样都是约束冲突,尺寸的约束冲突视图界面会用xib的约束。位置的约束冲突视图界面则用masonry的约束让人费解。还有待探索。it