MASonry 布局冲突快速定位
如果调试的时候,出现布局冲突,可以使用 MASAttachKeys 宏来给view添加key,提示信息就会提示出,是哪个view的哪个约束出冲突了!
用法如下
直接设置key
view1.mas_key = @"view1", view2.mas_key = @"view2";
或者
通过 MASAttachKeys(view1, view2);
给view1设置mas_key为view1以此类推
这样子在布局有冲突的时候,提示信息就会有 view1 view2 这样子的提示
实现原理如下
define MASAttachKeys(...) \
NSDictionary *keyPairs = NSDictionaryOfVariableBindings(__VA_ARGS__); \
for (id key in keyPairs.allKeys) { \
id obj = keyPairs[key]; \
NSAssert([obj respondsToSelector:@selector(setMas_key:)], \
@"Cannot attach mas_key to %@", obj); \
[obj setMas_key:key]; \
}
通过 NSDictionaryOfVariableBindings 宏来生成一个字典,比如:NSDictionaryOfVariableBindings(obj1,obj2.obj3),最后生成的字典是 {"obj1" : obj1, "obj2" : obj2, "obj3" : obj3}
然后通过 [obj setMas_key:key]; 完成赋值。
Demo
我们使用Monsary制造一个布局冲突玩玩。
UIView *v1 = [UIView new];
MASAttachKeys(v1);
[self.view addSubview:v1];
[v1 mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.top.offset(20);
make.size.mas_equalTo(CGSizeMake(50, 50));
}];
[v1 mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.top.offset(60);
make.size.mas_equalTo(CGSizeMake(70, 90));
}];
看看提示
BeautifyFaceDemo[6417:555809] [LayoutConstraints] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(
"<MASLayoutConstraint:0x6000000b0c80 UIView:v1.left == UIView:0x7fb4f8612740.left + 20>",
"<MASLayoutConstraint:0x6000000b1340 UIView:v1.left == UIView:0x7fb4f8612740.left + 60>"
)
Will attempt to recover by breaking constraint
<MASLayoutConstraint:0x6000000b1340 UIView:v1.left == UIView:0x7fb4f8612740.left + 60>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
2017-09-12 11:06:18.641562+0800 BeautifyFaceDemo[6417:555809] [LayoutConstraints] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(
"<MASLayoutConstraint:0x6000000b0f80 UIView:v1.top == UIView:0x7fb4f8612740.top + 20>",
"<MASLayoutConstraint:0x6000000b13a0 UIView:v1.top == UIView:0x7fb4f8612740.top + 60>"
)
Will attempt to recover by breaking constraint
<MASLayoutConstraint:0x6000000b13a0 UIView:v1.top == UIView:0x7fb4f8612740.top + 60>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
2017-09-12 11:06:18.642053+0800 BeautifyFaceDemo[6417:555809] [LayoutConstraints] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(
"<MASLayoutConstraint:0x6000000b1040 UIView:v1.width == 50>",
"<MASLayoutConstraint:0x6000000b1400 UIView:v1.width == 70>"
)
Will attempt to recover by breaking constraint
<MASLayoutConstraint:0x6000000b1400 UIView:v1.width == 70>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
2017-09-12 11:06:18.642516+0800 BeautifyFaceDemo[6417:555809] [LayoutConstraints] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(
"<MASLayoutConstraint:0x6000000b1100 UIView:v1.height == 50>",
"<MASLayoutConstraint:0x6000000b1460 UIView:v1.height == 90>"
)
Will attempt to recover by breaking constraint
<MASLayoutConstraint:0x6000000b1460 UIView:v1.height == 90>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
如上提示已经提示出 是 v1 的某个约束没写好。
为什么能打印出来?
之所以能打印出来,是因为
#import "NSLayoutConstraint+MASDebugAdditions.h"
这个类中,会附加一些调试信息,出现冲突的时候,系统会调用 NSLayoutConstraint 的 description方法,会紧跟着调用
+ (NSString *)descriptionForObject:(id)obj {
if ([obj respondsToSelector:@selector(mas_key)] && [obj mas_key]) {
return [NSString stringWithFormat:@"%@:%@", [obj class], [obj mas_key]];
}
return [NSString stringWithFormat:@"%@:%p", [obj class], obj];
}
然后把key 打印出来。
那么 NSLayoutConstraint 的 mas_key 在哪里赋值的呢,MASAttachKeys 只是给view设置了 mas_key ,
原因很简单,在 约束安装的时候,在 MASViewConstraint 的 install 的方法中
- (void)install {
if (self.hasBeenInstalled) {
return;
}
MAS_VIEW *firstLayoutItem = self.firstViewAttribute.item;
NSLayoutAttribute firstLayoutAttribute = self.firstViewAttribute.layoutAttribute;
MAS_VIEW *secondLayoutItem = self.secondViewAttribute.item;
NSLayoutAttribute secondLayoutAttribute = self.secondViewAttribute.layoutAttribute;
// alignment attributes must have a secondViewAttribute
// therefore we assume that is refering to superview
// eg make.left.equalTo(@10)
if (!self.firstViewAttribute.isSizeAttribute && !self.secondViewAttribute) {
secondLayoutItem = self.firstViewAttribute.view.superview;
secondLayoutAttribute = firstLayoutAttribute;
}
MASLayoutConstraint *layoutConstraint
= [MASLayoutConstraint constraintWithItem:firstLayoutItem
attribute:firstLayoutAttribute
relatedBy:self.layoutRelation
toItem:secondLayoutItem
attribute:secondLayoutAttribute
multiplier:self.layoutMultiplier
constant:self.layoutConstant];
layoutConstraint.priority = self.layoutPriority;
///设置调试信息
layoutConstraint.mas_key = self.mas_key;
注意事项
设置key必须在布局之前设置,否则无效!