Authored by Jonas Budelmann

remove ability to chain equality, less ambiguous if you need to reference constr…

…aint for animation or updating later on
@@ -158,12 +158,8 @@ @@ -158,12 +158,8 @@
158 [self.delegate addConstraint:self]; 158 [self.delegate addConstraint:self];
159 self.added = YES; 159 self.added = YES;
160 } 160 }
161 - for (id<MASConstraint> constraint in self.currentChildConstraints.copy) {  
162 - id<MASConstraint> newConstraint = block(constraint, attr);  
163 - if (newConstraint != constraint) {  
164 - [self.currentChildConstraints removeObject:constraint];  
165 - [self.currentChildConstraints addObject:newConstraint];  
166 - } 161 + for (id<MASConstraint> constraint in self.currentChildConstraints) {
  162 + block(constraint, attr);
167 } 163 }
168 return self; 164 return self;
169 }; 165 };
@@ -199,7 +195,6 @@ @@ -199,7 +195,6 @@
199 for (id<MASConstraint> constraint in self.completedChildConstraints) { 195 for (id<MASConstraint> constraint in self.completedChildConstraints) {
200 [constraint commit]; 196 [constraint commit];
201 } 197 }
202 - [self.currentChildConstraints removeAllObjects];  
203 [self.completedChildConstraints removeAllObjects]; 198 [self.completedChildConstraints removeAllObjects];
204 } 199 }
205 200
@@ -63,18 +63,6 @@ @@ -63,18 +63,6 @@
63 } 63 }
64 } 64 }
65 65
66 -- (instancetype)cloneIfNeeded {  
67 - if (self.hasLayoutRelation) {  
68 - MASViewAttribute *firstViewAttribute = [[MASViewAttribute alloc] initWithView:self.firstViewAttribute.view layoutAttribute:self.firstViewAttribute.layoutAttribute];  
69 -  
70 - MASViewConstraint *viewConstraint = [[MASViewConstraint alloc] initWithFirstViewAttribute:firstViewAttribute];  
71 - viewConstraint.delegate = self.delegate;  
72 - viewConstraint.layoutRelation = self.layoutRelation;  
73 - return viewConstraint;  
74 - }  
75 - return self;  
76 -}  
77 -  
78 #pragma mark - NSLayoutConstraint constant proxies 66 #pragma mark - NSLayoutConstraint constant proxies
79 67
80 - (id<MASConstraint> (^)(UIEdgeInsets))insets { 68 - (id<MASConstraint> (^)(UIEdgeInsets))insets {
@@ -190,40 +178,34 @@ @@ -190,40 +178,34 @@
190 178
191 - (id<MASConstraint> (^)(id))equalTo { 179 - (id<MASConstraint> (^)(id))equalTo {
192 return ^id(id attr) { 180 return ^id(id attr) {
193 - NSAssert(!self.hasBeenCommitted,  
194 - @"Cannot modify constraint equal relation after it has been committed"); 181 + NSAssert(!self.hasLayoutRelation, @"Redefinition of constraint relation");
195 182
196 - MASViewConstraint *viewConstraint = [self cloneIfNeeded];  
197 - viewConstraint.layoutRelation = NSLayoutRelationEqual;  
198 - viewConstraint.secondViewAttribute = attr;  
199 - [viewConstraint.delegate addConstraint:viewConstraint];  
200 - return viewConstraint; 183 + self.layoutRelation = NSLayoutRelationEqual;
  184 + self.secondViewAttribute = attr;
  185 + [self.delegate addConstraint:self];
  186 + return self;
201 }; 187 };
202 } 188 }
203 189
204 - (id<MASConstraint> (^)(id))greaterThanOrEqualTo { 190 - (id<MASConstraint> (^)(id))greaterThanOrEqualTo {
205 return ^id(id attr) { 191 return ^id(id attr) {
206 - NSAssert(!self.hasBeenCommitted,  
207 - @"Cannot modify constraint greaterThanOrEqual relation after it has been committed"); 192 + NSAssert(!self.hasLayoutRelation, @"Redefinition of constraint relation");
208 193
209 - MASViewConstraint *viewConstraint = [self cloneIfNeeded];  
210 - viewConstraint.layoutRelation = NSLayoutRelationGreaterThanOrEqual;  
211 - viewConstraint.secondViewAttribute = attr;  
212 - [viewConstraint.delegate addConstraint:viewConstraint];  
213 - return viewConstraint; 194 + self.layoutRelation = NSLayoutRelationGreaterThanOrEqual;
  195 + self.secondViewAttribute = attr;
  196 + [self.delegate addConstraint:self];
  197 + return self;
214 }; 198 };
215 } 199 }
216 200
217 - (id<MASConstraint> (^)(id))lessThanOrEqualTo { 201 - (id<MASConstraint> (^)(id))lessThanOrEqualTo {
218 return ^id(id attr) { 202 return ^id(id attr) {
219 - NSAssert(!self.hasBeenCommitted,  
220 - @"Cannot modify constraint lessThanOrEqual relation after it has been committed"); 203 + NSAssert(!self.hasLayoutRelation, @"Redefinition of constraint relation");
221 204
222 - MASViewConstraint *viewConstraint = [self cloneIfNeeded];  
223 - viewConstraint.layoutRelation = NSLayoutRelationLessThanOrEqual;  
224 - viewConstraint.secondViewAttribute = attr;  
225 - [viewConstraint.delegate addConstraint:viewConstraint];  
226 - return viewConstraint; 205 + self.layoutRelation = NSLayoutRelationLessThanOrEqual;
  206 + self.secondViewAttribute = attr;
  207 + [self.delegate addConstraint:self];
  208 + return self;
227 }; 209 };
228 } 210 }
229 211
@@ -49,7 +49,6 @@ @@ -49,7 +49,6 @@
49 [self.animatableConstraints addObjectsFromArray:@[ 49 [self.animatableConstraints addObjectsFromArray:@[
50 make.edges.equalTo(superview).insets(paddingInsets).priorityLow(), 50 make.edges.equalTo(superview).insets(paddingInsets).priorityLow(),
51 make.bottom.equalTo(view3.mas_top).offset(-padding), 51 make.bottom.equalTo(view3.mas_top).offset(-padding),
52 - make.right.equalTo(view2.mas_left).offset(-padding),  
53 ]]; 52 ]];
54 53
55 make.size.equalTo(view2); 54 make.size.equalTo(view2);
@@ -70,11 +69,8 @@ @@ -70,11 +69,8 @@
70 [view3 mas_makeConstraints:^(MASConstraintMaker *make) { 69 [view3 mas_makeConstraints:^(MASConstraintMaker *make) {
71 [self.animatableConstraints addObjectsFromArray:@[ 70 [self.animatableConstraints addObjectsFromArray:@[
72 make.edges.equalTo(superview).insets(paddingInsets).priorityLow(), 71 make.edges.equalTo(superview).insets(paddingInsets).priorityLow(),
73 - make.top.equalTo(view1.mas_bottom).offset(padding),  
74 ]]; 72 ]];
75 73
76 - //TODO or pass an array  
77 - //constraints.height.equal(superview.subviews);  
78 make.height.equalTo(view1.mas_height); 74 make.height.equalTo(view1.mas_height);
79 make.height.equalTo(view2.mas_height); 75 make.height.equalTo(view2.mas_height);
80 }]; 76 }];
@@ -83,6 +79,7 @@ @@ -83,6 +79,7 @@
83 } 79 }
84 80
85 - (void)didMoveToSuperview { 81 - (void)didMoveToSuperview {
  82 + [self layoutIfNeeded];
86 [self startAnimatingWithInvertedInsets:NO]; 83 [self startAnimatingWithInvertedInsets:NO];
87 } 84 }
88 85
@@ -43,11 +43,9 @@ @@ -43,11 +43,9 @@
43 make.bottom.equalTo(view3.top).offset(-padding); 43 make.bottom.equalTo(view3.top).offset(-padding);
44 make.right.equalTo(view2.left).offset(-padding); 44 make.right.equalTo(view2.left).offset(-padding);
45 make.width.equalTo(view2.width); 45 make.width.equalTo(view2.width);
46 -  
47 - //you can chain same attribute  
48 - make.height  
49 - .equalTo(view2.height)  
50 - .equalTo(view3.height); 46 +
  47 + make.height.equalTo(view2.height);
  48 + make.height.equalTo(view3.height);
51 }]; 49 }];
52 50
53 //with is semantic and option 51 //with is semantic and option
@@ -58,7 +56,6 @@ @@ -58,7 +56,6 @@
58 make.right.equalTo(superview.mas_right).offset(-padding); 56 make.right.equalTo(superview.mas_right).offset(-padding);
59 make.width.equalTo(view1.mas_width); 57 make.width.equalTo(view1.mas_width);
60 58
61 - //or define it multiple times  
62 make.height.equalTo(view1.mas_height); 59 make.height.equalTo(view1.mas_height);
63 make.height.equalTo(view3.mas_height); 60 make.height.equalTo(view3.mas_height);
64 }]; 61 }];
@@ -69,12 +66,10 @@ @@ -69,12 +66,10 @@
69 make.bottom.equalTo(superview.mas_bottom).offset(-padding); 66 make.bottom.equalTo(superview.mas_bottom).offset(-padding);
70 make.right.equalTo(superview.mas_right).offset(-padding); 67 make.right.equalTo(superview.mas_right).offset(-padding);
71 68
72 - //TODO or pass an array  
73 - //constraints.height.equal(superview.subviews);  
74 make.height.equalTo(view1.mas_height); 69 make.height.equalTo(view1.mas_height);
75 make.height.equalTo(view2.mas_height); 70 make.height.equalTo(view2.mas_height);
76 }]; 71 }];
77 - 72 +
78 return self; 73 return self;
79 } 74 }
80 75
@@ -20,6 +20,7 @@ @@ -20,6 +20,7 @@
20 @interface MASViewConstraint () 20 @interface MASViewConstraint ()
21 21
22 @property (nonatomic, assign) CGFloat layoutConstant; 22 @property (nonatomic, assign) CGFloat layoutConstant;
  23 +@property (nonatomic, assign) MASLayoutPriority layoutPriority;
23 24
24 @end 25 @end
25 26
@@ -100,9 +101,7 @@ it(@"should complete children", ^{ @@ -100,9 +101,7 @@ it(@"should complete children", ^{
100 101
101 //first equality statement 102 //first equality statement
102 composite.equalTo(newView).sizeOffset(CGSizeMake(90, 30)); 103 composite.equalTo(newView).sizeOffset(CGSizeMake(90, 30));
103 -  
104 - [verify(delegate) addConstraint:(id)composite];  
105 - 104 +
106 expect(composite.completedChildConstraints).to.haveCountOf(2); 105 expect(composite.completedChildConstraints).to.haveCountOf(2);
107 expect(composite.currentChildConstraints).to.haveCountOf(2); 106 expect(composite.currentChildConstraints).to.haveCountOf(2);
108 107
@@ -110,38 +109,20 @@ it(@"should complete children", ^{ @@ -110,38 +109,20 @@ it(@"should complete children", ^{
110 expect(viewConstraint.secondViewAttribute.view).to.beIdenticalTo(newView); 109 expect(viewConstraint.secondViewAttribute.view).to.beIdenticalTo(newView);
111 expect(viewConstraint.secondViewAttribute.layoutAttribute).to.equal(NSLayoutAttributeWidth); 110 expect(viewConstraint.secondViewAttribute.layoutAttribute).to.equal(NSLayoutAttributeWidth);
112 expect(viewConstraint.layoutConstant).to.equal(90); 111 expect(viewConstraint.layoutConstant).to.equal(90);
  112 + expect(viewConstraint.layoutPriority).to.equal(MASLayoutPriorityRequired);
113 113
114 viewConstraint = composite.completedChildConstraints[1]; 114 viewConstraint = composite.completedChildConstraints[1];
115 expect(viewConstraint.secondViewAttribute.view).to.beIdenticalTo(newView); 115 expect(viewConstraint.secondViewAttribute.view).to.beIdenticalTo(newView);
116 expect(viewConstraint.secondViewAttribute.layoutAttribute).to.equal(NSLayoutAttributeHeight); 116 expect(viewConstraint.secondViewAttribute.layoutAttribute).to.equal(NSLayoutAttributeHeight);
117 expect(viewConstraint.layoutConstant).to.equal(30); 117 expect(viewConstraint.layoutConstant).to.equal(30);
  118 + expect(viewConstraint.layoutPriority).to.equal(MASLayoutPriorityRequired);
118 119
119 - //chain another equality statement  
120 - composite.greaterThanOrEqualTo(@6);  
121 - expect(composite.completedChildConstraints).to.haveCountOf(4);  
122 - expect(composite.currentChildConstraints).to.haveCountOf(2);  
123 -  
124 - viewConstraint = composite.completedChildConstraints[2];  
125 - expect(viewConstraint.secondViewAttribute.view).to.beNil();  
126 - expect(viewConstraint.secondViewAttribute.layoutAttribute).to.equal(0);  
127 - expect(viewConstraint.layoutConstant).to.equal(6);  
128 -  
129 - viewConstraint = composite.completedChildConstraints[2];  
130 - expect(viewConstraint.secondViewAttribute.view).to.beNil();  
131 - expect(viewConstraint.secondViewAttribute.layoutAttribute).to.equal(0);  
132 - expect(viewConstraint.layoutConstant).to.equal(6);  
133 -  
134 - //still referencing same view  
135 - viewConstraint = composite.currentChildConstraints[0];  
136 - expect(viewConstraint.firstViewAttribute.view).to.beIdenticalTo(composite.view);  
137 - expect(viewConstraint.firstViewAttribute.layoutAttribute).to.equal(NSLayoutAttributeWidth);  
138 -  
139 - viewConstraint = composite.currentChildConstraints[1];  
140 - expect(viewConstraint.firstViewAttribute.view).to.beIdenticalTo(composite.view);  
141 - expect(viewConstraint.firstViewAttribute.layoutAttribute).to.equal(NSLayoutAttributeHeight); 120 + //new current
  121 + expect(composite.completedChildConstraints[0]).to.beIdenticalTo(composite.currentChildConstraints[0]);
  122 + expect(composite.completedChildConstraints[1]).to.beIdenticalTo(composite.currentChildConstraints[1]);
142 }); 123 });
143 124
144 -it(@"should remove all on commit", ^{ 125 +it(@"should remove completed on commit", ^{
145 composite = [[MASCompositeConstraint alloc] initWithView:view type:MASCompositeViewConstraintTypeSize]; 126 composite = [[MASCompositeConstraint alloc] initWithView:view type:MASCompositeViewConstraintTypeSize];
146 composite.delegate = delegate; 127 composite.delegate = delegate;
147 UIView *newView = UIView.new; 128 UIView *newView = UIView.new;
@@ -158,7 +139,7 @@ it(@"should remove all on commit", ^{ @@ -158,7 +139,7 @@ it(@"should remove all on commit", ^{
158 [composite commit]; 139 [composite commit];
159 140
160 expect(composite.completedChildConstraints).to.haveCountOf(0); 141 expect(composite.completedChildConstraints).to.haveCountOf(0);
161 - expect(composite.currentChildConstraints).to.haveCountOf(0); 142 + expect(composite.currentChildConstraints).to.haveCountOf(2);
162 }); 143 });
163 144
164 SpecEnd 145 SpecEnd
@@ -43,9 +43,9 @@ beforeEach(^{ @@ -43,9 +43,9 @@ beforeEach(^{
43 [superview addSubview:otherView]; 43 [superview addSubview:otherView];
44 }); 44 });
45 45
46 -describe(@"equality chaining", ^{ 46 +describe(@"create equality constraint", ^{
47 47
48 - it(@"should return same constraint when encountering equal for first time", ^{ 48 + it(@"should create equal constraint", ^{
49 MASViewAttribute *secondViewAttribute = otherView.mas_top; 49 MASViewAttribute *secondViewAttribute = otherView.mas_top;
50 MASViewConstraint *newConstraint = constraint.equalTo(secondViewAttribute); 50 MASViewConstraint *newConstraint = constraint.equalTo(secondViewAttribute);
51 51
@@ -55,17 +55,7 @@ describe(@"equality chaining", ^{ @@ -55,17 +55,7 @@ describe(@"equality chaining", ^{
55 expect(constraint.layoutRelation).to.equal(NSLayoutRelationEqual); 55 expect(constraint.layoutRelation).to.equal(NSLayoutRelationEqual);
56 }); 56 });
57 57
58 - it(@"should start new constraint when encountering equal subsequently", ^{  
59 - MASViewAttribute *secondViewAttribute = otherView.mas_top;  
60 - constraint.greaterThanOrEqualTo(secondViewAttribute);  
61 - MASViewConstraint *newConstraint = constraint.equalTo(secondViewAttribute);  
62 -  
63 - [verify(constraint.delegate) addConstraint:(id)constraint];  
64 - [verify(constraint.delegate) addConstraint:(id)newConstraint];  
65 - expect(newConstraint).notTo.beIdenticalTo(constraint);  
66 - });  
67 -  
68 - it(@"should return same constraint when encountering greaterThanOrEqual for first time", ^{ 58 + it(@"should create greaterThanOrEqual constraint", ^{
69 MASViewAttribute *secondViewAttribute = otherView.mas_top; 59 MASViewAttribute *secondViewAttribute = otherView.mas_top;
70 MASViewConstraint *newConstraint = constraint.greaterThanOrEqualTo(secondViewAttribute); 60 MASViewConstraint *newConstraint = constraint.greaterThanOrEqualTo(secondViewAttribute);
71 61
@@ -75,17 +65,7 @@ describe(@"equality chaining", ^{ @@ -75,17 +65,7 @@ describe(@"equality chaining", ^{
75 expect(constraint.layoutRelation).to.equal(NSLayoutRelationGreaterThanOrEqual); 65 expect(constraint.layoutRelation).to.equal(NSLayoutRelationGreaterThanOrEqual);
76 }); 66 });
77 67
78 - it(@"should start new constraint when encountering greaterThanOrEqual subsequently", ^{  
79 - MASViewAttribute *secondViewAttribute = otherView.mas_top;  
80 - constraint.lessThanOrEqualTo(secondViewAttribute);  
81 - MASViewConstraint *newConstraint = constraint.greaterThanOrEqualTo(secondViewAttribute);  
82 -  
83 - [verify(constraint.delegate) addConstraint:(id)constraint];  
84 - [verify(constraint.delegate) addConstraint:(id)newConstraint];  
85 - expect(newConstraint).notTo.beIdenticalTo(constraint);  
86 - });  
87 -  
88 - it(@"should return same constraint when encountering lessThanOrEqual for first time", ^{ 68 + it(@"create lessThanOrEqual constraint", ^{
89 MASViewAttribute *secondViewAttribute = otherView.mas_top; 69 MASViewAttribute *secondViewAttribute = otherView.mas_top;
90 MASViewConstraint *newConstraint = constraint.lessThanOrEqualTo(secondViewAttribute); 70 MASViewConstraint *newConstraint = constraint.lessThanOrEqualTo(secondViewAttribute);
91 71
@@ -95,37 +75,27 @@ describe(@"equality chaining", ^{ @@ -95,37 +75,27 @@ describe(@"equality chaining", ^{
95 expect(constraint.layoutRelation).to.equal(NSLayoutRelationLessThanOrEqual); 75 expect(constraint.layoutRelation).to.equal(NSLayoutRelationLessThanOrEqual);
96 }); 76 });
97 77
98 - it(@"should start new constraint when encountering lessThanOrEqual subsequently", ^{ 78 + it(@"should not allow update of equal", ^{
99 MASViewAttribute *secondViewAttribute = otherView.mas_top; 79 MASViewAttribute *secondViewAttribute = otherView.mas_top;
100 - constraint.equalTo(secondViewAttribute);  
101 - MASViewConstraint *newConstraint = constraint.lessThanOrEqualTo(secondViewAttribute);  
102 -  
103 - [verify(constraint.delegate) addConstraint:(id)constraint];  
104 - [verify(constraint.delegate) addConstraint:(id)newConstraint];  
105 - expect(newConstraint).notTo.beIdenticalTo(constraint);  
106 - });  
107 -  
108 - it(@"should not allow update of equal once layoutconstraint is created", ^{  
109 - MASViewAttribute *secondViewAttribute = otherView.mas_top;  
110 - [constraint commit]; 80 + constraint.lessThanOrEqualTo(secondViewAttribute);
111 81
112 expect(^{ 82 expect(^{
113 constraint.equalTo(secondViewAttribute); 83 constraint.equalTo(secondViewAttribute);
114 }).to.raise(@"NSInternalInconsistencyException"); 84 }).to.raise(@"NSInternalInconsistencyException");
115 }); 85 });
116 86
117 - it(@"should not allow update of lessThanOrEqual once layoutconstraint is created", ^{ 87 + it(@"should not allow update of lessThanOrEqual", ^{
118 MASViewAttribute *secondViewAttribute = otherView.mas_top; 88 MASViewAttribute *secondViewAttribute = otherView.mas_top;
119 - [constraint commit]; 89 + constraint.equalTo(secondViewAttribute);
120 90
121 expect(^{ 91 expect(^{
122 constraint.lessThanOrEqualTo(secondViewAttribute); 92 constraint.lessThanOrEqualTo(secondViewAttribute);
123 }).to.raise(@"NSInternalInconsistencyException"); 93 }).to.raise(@"NSInternalInconsistencyException");
124 }); 94 });
125 95
126 - it(@"should not allow update of greaterThanOrEqual once layoutconstraint is created", ^{ 96 + it(@"should not allow update of greaterThanOrEqual", ^{
127 MASViewAttribute *secondViewAttribute = otherView.mas_top; 97 MASViewAttribute *secondViewAttribute = otherView.mas_top;
128 - [constraint commit]; 98 + constraint.greaterThanOrEqualTo(secondViewAttribute);
129 99
130 expect(^{ 100 expect(^{
131 constraint.greaterThanOrEqualTo(secondViewAttribute); 101 constraint.greaterThanOrEqualTo(secondViewAttribute);
@@ -114,7 +114,6 @@ if you want view.left to be greater than or equal to label.left : @@ -114,7 +114,6 @@ if you want view.left to be greater than or equal to label.left :
114 ```obj-c 114 ```obj-c
115 //these two constraints are exactly the same 115 //these two constraints are exactly the same
116 make.left.greaterThanOrEqualTo(label); 116 make.left.greaterThanOrEqualTo(label);
117 -  
118 make.left.greaterThanOrEqualTo(label.mas_left); 117 make.left.greaterThanOrEqualTo(label.mas_left);
119 ``` 118 ```
120 119
@@ -123,9 +122,8 @@ make.left.greaterThanOrEqualTo(label.mas_left); @@ -123,9 +122,8 @@ make.left.greaterThanOrEqualTo(label.mas_left);
123 if you want to set view to have a minimum and maximum width you could pass a number to the equality blocks: 122 if you want to set view to have a minimum and maximum width you could pass a number to the equality blocks:
124 123
125 ```obj-c 124 ```obj-c
126 -make.width  
127 - .greaterThanOrEqualTo(@200)  
128 - .lessThanOrEqualTo(@400) 125 +make.width.greaterThanOrEqualTo(@200);
  126 +make.width.lessThanOrEqualTo(@400)
129 ``` 127 ```
130 128
131 ## Learn to prioritize 129 ## Learn to prioritize