Authored by Jonas Budelmann

Merge branch 'auto_update' of https://github.com/cloudkite/Masonry

@@ -18,6 +18,7 @@ @@ -18,6 +18,7 @@
18 @implementation MASCompositeConstraint 18 @implementation MASCompositeConstraint
19 19
20 @synthesize delegate = _delegate; 20 @synthesize delegate = _delegate;
  21 +@synthesize updateExisting = _updateExisting;
21 22
22 - (id)initWithChildren:(NSArray *)children { 23 - (id)initWithChildren:(NSArray *)children {
23 self = [super init]; 24 self = [super init];
@@ -181,6 +182,7 @@ @@ -181,6 +182,7 @@
181 182
182 - (void)install { 183 - (void)install {
183 for (id<MASConstraint> constraint in self.childConstraints) { 184 for (id<MASConstraint> constraint in self.childConstraints) {
  185 + constraint.updateExisting = self.updateExisting;
184 [constraint install]; 186 [constraint install];
185 } 187 }
186 } 188 }
@@ -114,6 +114,11 @@ @@ -114,6 +114,11 @@
114 @property (nonatomic, copy, readonly) id<MASConstraint> (^key)(id key); 114 @property (nonatomic, copy, readonly) id<MASConstraint> (^key)(id key);
115 115
116 /** 116 /**
  117 + * Whether or not to check for an existing constraint instead of adding constraint
  118 + */
  119 +@property (nonatomic, assign) BOOL updateExisting;
  120 +
  121 +/**
117 * Creates a NSLayoutConstraint. The constraint is installed to the first view or the or the closest common superview of the first and second view. 122 * Creates a NSLayoutConstraint. The constraint is installed to the first view or the or the closest common superview of the first and second view.
118 */ 123 */
119 - (void)install; 124 - (void)install;
@@ -54,6 +54,11 @@ @@ -54,6 +54,11 @@
54 @property (nonatomic, strong, readonly) id<MASConstraint> center; 54 @property (nonatomic, strong, readonly) id<MASConstraint> center;
55 55
56 /** 56 /**
  57 + * Whether or not to check for an existing constraint instead of adding constraint
  58 + */
  59 +@property (nonatomic, assign) BOOL updateExisting;
  60 +
  61 +/**
57 * initialises the maker with a default view 62 * initialises the maker with a default view
58 * 63 *
59 * @param view any MASConstrait are created with this view as the first item 64 * @param view any MASConstrait are created with this view as the first item
@@ -34,6 +34,7 @@ @@ -34,6 +34,7 @@
34 - (NSArray *)install { 34 - (NSArray *)install {
35 NSArray *constraints = self.constraints.copy; 35 NSArray *constraints = self.constraints.copy;
36 for (id<MASConstraint> constraint in constraints) { 36 for (id<MASConstraint> constraint in constraints) {
  37 + constraint.updateExisting = self.updateExisting;
37 [constraint install]; 38 [constraint install];
38 } 39 }
39 [self.constraints removeAllObjects]; 40 [self.constraints removeAllObjects];
@@ -28,6 +28,7 @@ @@ -28,6 +28,7 @@
28 @implementation MASViewConstraint 28 @implementation MASViewConstraint
29 29
30 @synthesize delegate = _delegate; 30 @synthesize delegate = _delegate;
  31 +@synthesize updateExisting = _updateExisting;
31 32
32 - (id)initWithFirstViewAttribute:(MASViewAttribute *)firstViewAttribute { 33 - (id)initWithFirstViewAttribute:(MASViewAttribute *)firstViewAttribute {
33 self = [super init]; 34 self = [super init];
@@ -291,15 +292,44 @@ @@ -291,15 +292,44 @@
291 @"couldn't find a common superview for %@ and %@", 292 @"couldn't find a common superview for %@ and %@",
292 firstLayoutItem, secondLayoutItem); 293 firstLayoutItem, secondLayoutItem);
293 self.installedView = closestCommonSuperview; 294 self.installedView = closestCommonSuperview;
294 - [closestCommonSuperview addConstraint:layoutConstraint];  
295 - self.layoutConstraint = layoutConstraint;  
296 } else { 295 } else {
297 self.installedView = firstLayoutItem; 296 self.installedView = firstLayoutItem;
298 - [firstLayoutItem addConstraint:layoutConstraint]; 297 + }
  298 +
  299 +
  300 + MASLayoutConstraint *existingConstraint = nil;
  301 + if (self.updateExisting) {
  302 + existingConstraint = [self layoutConstraintSimiliarTo:layoutConstraint];
  303 + }
  304 + if (existingConstraint) {
  305 + // just update the constant
  306 + existingConstraint.constant = layoutConstraint.constant;
  307 + self.layoutConstraint = existingConstraint;
  308 + } else {
  309 + [self.installedView addConstraint:layoutConstraint];
299 self.layoutConstraint = layoutConstraint; 310 self.layoutConstraint = layoutConstraint;
300 } 311 }
301 } 312 }
302 313
  314 +- (MASLayoutConstraint *)layoutConstraintSimiliarTo:(MASLayoutConstraint *)layoutConstraint {
  315 + // check if any constraints are the same apart from the only mutable property constant
  316 +
  317 + // go through constraints in reverse as we do not want to match auto-resizing or interface builder constraints
  318 + // and they are likely to be added first.
  319 + for (NSLayoutConstraint *existingConstraint in self.installedView.constraints.reverseObjectEnumerator) {
  320 + if (![existingConstraint isKindOfClass:MASLayoutConstraint.class]) continue;
  321 + if (existingConstraint.firstItem != layoutConstraint.firstItem) continue;
  322 + if (existingConstraint.secondItem != layoutConstraint.secondItem) continue;
  323 + if (existingConstraint.firstAttribute != layoutConstraint.firstAttribute) continue;
  324 + if (existingConstraint.secondAttribute != layoutConstraint.secondAttribute) continue;
  325 + if (existingConstraint.multiplier != layoutConstraint.multiplier) continue;
  326 + if (existingConstraint.priority != layoutConstraint.priority) continue;
  327 +
  328 + return (id)existingConstraint;
  329 + }
  330 + return nil;
  331 +}
  332 +
303 - (void)uninstall { 333 - (void)uninstall {
304 [self.installedView removeConstraint:self.layoutConstraint]; 334 [self.installedView removeConstraint:self.layoutConstraint];
305 self.layoutConstraint = nil; 335 self.layoutConstraint = nil;
@@ -55,4 +55,15 @@ @@ -55,4 +55,15 @@
55 */ 55 */
56 - (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *make))block; 56 - (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *make))block;
57 57
  58 +/**
  59 + * Creates a MASConstraintMaker with the callee view.
  60 + * Any constraints defined are added to the view or the appropriate superview once the block has finished executing.
  61 + * If an existing constraint exists then it will be updated instead.
  62 + *
  63 + * @param block scope within which you can build up the constraints which you wish to apply to the view.
  64 + *
  65 + * @return Array of created/updated MASConstraints
  66 + */
  67 +- (NSArray *)mas_updateConstraints:(void(^)(MASConstraintMaker *make))block;
  68 +
58 @end 69 @end
@@ -18,6 +18,14 @@ @@ -18,6 +18,14 @@
18 return [constraintMaker install]; 18 return [constraintMaker install];
19 } 19 }
20 20
  21 +- (NSArray *)mas_updateConstraints:(void(^)(MASConstraintMaker *))block {
  22 + self.translatesAutoresizingMaskIntoConstraints = NO;
  23 + MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];
  24 + constraintMaker.updateExisting = YES;
  25 + block(constraintMaker);
  26 + return [constraintMaker install];
  27 +}
  28 +
21 #pragma mark - NSLayoutAttribute properties 29 #pragma mark - NSLayoutAttribute properties
22 30
23 - (MASViewAttribute *)mas_left { 31 - (MASViewAttribute *)mas_left {
@@ -29,6 +29,7 @@ @@ -29,6 +29,7 @@
29 @property (nonatomic, strong, readonly) MASViewAttribute *baseline; 29 @property (nonatomic, strong, readonly) MASViewAttribute *baseline;
30 30
31 - (NSArray *)makeConstraints:(void(^)(MASConstraintMaker *make))block; 31 - (NSArray *)makeConstraints:(void(^)(MASConstraintMaker *make))block;
  32 +- (NSArray *)updateConstraints:(void(^)(MASConstraintMaker *make))block;
32 33
33 @end 34 @end
34 35
@@ -55,6 +56,10 @@ MAS_ATTR_FORWARD(baseline); @@ -55,6 +56,10 @@ MAS_ATTR_FORWARD(baseline);
55 return [self mas_makeConstraints:block]; 56 return [self mas_makeConstraints:block];
56 } 57 }
57 58
  59 +- (NSArray *)updateConstraints:(void(^)(MASConstraintMaker *))block {
  60 + return [self mas_updateConstraints:block];
  61 +}
  62 +
58 @end 63 @end
59 64
60 #endif 65 #endif
@@ -7,6 +7,7 @@ @@ -7,6 +7,7 @@
7 objects = { 7 objects = {
8 8
9 /* Begin PBXBuildFile section */ 9 /* Begin PBXBuildFile section */
  10 + DD175E6A182639FB0099129A /* MASExampleUpdateView.m in Sources */ = {isa = PBXBuildFile; fileRef = DD175E69182639FB0099129A /* MASExampleUpdateView.m */; };
10 DD52F22B179CAD57005CD195 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DD52F22A179CAD57005CD195 /* UIKit.framework */; }; 11 DD52F22B179CAD57005CD195 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DD52F22A179CAD57005CD195 /* UIKit.framework */; };
11 DD52F22D179CAD57005CD195 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DD52F22C179CAD57005CD195 /* Foundation.framework */; }; 12 DD52F22D179CAD57005CD195 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DD52F22C179CAD57005CD195 /* Foundation.framework */; };
12 DD52F22F179CAD57005CD195 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DD52F22E179CAD57005CD195 /* CoreGraphics.framework */; }; 13 DD52F22F179CAD57005CD195 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DD52F22E179CAD57005CD195 /* CoreGraphics.framework */; };
@@ -31,6 +32,8 @@ @@ -31,6 +32,8 @@
31 /* End PBXBuildFile section */ 32 /* End PBXBuildFile section */
32 33
33 /* Begin PBXFileReference section */ 34 /* Begin PBXFileReference section */
  35 + DD175E68182639FB0099129A /* MASExampleUpdateView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MASExampleUpdateView.h; sourceTree = "<group>"; };
  36 + DD175E69182639FB0099129A /* MASExampleUpdateView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MASExampleUpdateView.m; sourceTree = "<group>"; };
34 DD52F227179CAD57005CD195 /* Masonry iOS Examples.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Masonry iOS Examples.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 37 DD52F227179CAD57005CD195 /* Masonry iOS Examples.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Masonry iOS Examples.app"; sourceTree = BUILT_PRODUCTS_DIR; };
35 DD52F22A179CAD57005CD195 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 38 DD52F22A179CAD57005CD195 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
36 DD52F22C179CAD57005CD195 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 39 DD52F22C179CAD57005CD195 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
@@ -157,6 +160,8 @@ @@ -157,6 +160,8 @@
157 DD7CC17517ACE990007A469E /* MASExampleDebuggingView.m */, 160 DD7CC17517ACE990007A469E /* MASExampleDebuggingView.m */,
158 DDDF60CA181915E300BF7B8B /* MASExampleLabelView.h */, 161 DDDF60CA181915E300BF7B8B /* MASExampleLabelView.h */,
159 DDDF60CB181915E300BF7B8B /* MASExampleLabelView.m */, 162 DDDF60CB181915E300BF7B8B /* MASExampleLabelView.m */,
  163 + DD175E68182639FB0099129A /* MASExampleUpdateView.h */,
  164 + DD175E69182639FB0099129A /* MASExampleUpdateView.m */,
160 ); 165 );
161 name = Views; 166 name = Views;
162 sourceTree = "<group>"; 167 sourceTree = "<group>";
@@ -261,6 +266,7 @@ @@ -261,6 +266,7 @@
261 isa = PBXSourcesBuildPhase; 266 isa = PBXSourcesBuildPhase;
262 buildActionMask = 2147483647; 267 buildActionMask = 2147483647;
263 files = ( 268 files = (
  269 + DD175E6A182639FB0099129A /* MASExampleUpdateView.m in Sources */,
264 DD52F237179CAD57005CD195 /* main.m in Sources */, 270 DD52F237179CAD57005CD195 /* main.m in Sources */,
265 DD52F23B179CAD57005CD195 /* MASAppDelegate.m in Sources */, 271 DD52F23B179CAD57005CD195 /* MASAppDelegate.m in Sources */,
266 DD52F251179CADC0005CD195 /* MASExampleBasicView.m in Sources */, 272 DD52F251179CADC0005CD195 /* MASExampleBasicView.m in Sources */,
@@ -14,6 +14,7 @@ @@ -14,6 +14,7 @@
14 #import "MASExampleAnimatedView.h" 14 #import "MASExampleAnimatedView.h"
15 #import "MASExampleDebuggingView.h" 15 #import "MASExampleDebuggingView.h"
16 #import "MASExampleLabelView.h" 16 #import "MASExampleLabelView.h"
  17 +#import "MASExampleUpdateView.h"
17 18
18 static NSString * const kMASCellReuseIdentifier = @"kMASCellReuseIdentifier"; 19 static NSString * const kMASCellReuseIdentifier = @"kMASCellReuseIdentifier";
19 20
@@ -44,6 +45,8 @@ static NSString * const kMASCellReuseIdentifier = @"kMASCellReuseIdentifier"; @@ -44,6 +45,8 @@ static NSString * const kMASCellReuseIdentifier = @"kMASCellReuseIdentifier";
44 viewClass:MASExampleDebuggingView.class], 45 viewClass:MASExampleDebuggingView.class],
45 [[MASExampleViewController alloc] initWithTitle:@"Bacony Labels" 46 [[MASExampleViewController alloc] initWithTitle:@"Bacony Labels"
46 viewClass:MASExampleLabelView.class], 47 viewClass:MASExampleLabelView.class],
  48 + [[MASExampleViewController alloc] initWithTitle:@"Update constraints"
  49 + viewClass:MASExampleUpdateView.class],
47 ]; 50 ];
48 51
49 return self; 52 return self;
  1 +//
  2 +// MASExampleUpdateView.h
  3 +// Masonry iOS Examples
  4 +//
  5 +// Created by Jonas Budelmann on 3/11/13.
  6 +// Copyright (c) 2013 Jonas Budelmann. All rights reserved.
  7 +//
  8 +
  9 +#import <UIKit/UIKit.h>
  10 +
  11 +@interface MASExampleUpdateView : UIView
  12 +
  13 +@end
  1 +//
  2 +// MASExampleUpdateView.m
  3 +// Masonry iOS Examples
  4 +//
  5 +// Created by Jonas Budelmann on 3/11/13.
  6 +// Copyright (c) 2013 Jonas Budelmann. All rights reserved.
  7 +//
  8 +
  9 +#import "MASExampleUpdateView.h"
  10 +
  11 +@interface MASExampleUpdateView ()
  12 +
  13 +@property (nonatomic, strong) UIButton *growingButton;
  14 +@property (nonatomic, assign) CGSize buttonSize;
  15 +
  16 +@end
  17 +
  18 +@implementation MASExampleUpdateView
  19 +
  20 +- (id)init {
  21 + self = [super init];
  22 + if (!self) return nil;
  23 +
  24 + self.growingButton = [UIButton buttonWithType:UIButtonTypeSystem];
  25 + [self.growingButton setTitle:@"Grow Me!" forState:UIControlStateNormal];
  26 + self.growingButton.layer.borderColor = UIColor.greenColor.CGColor;
  27 + self.growingButton.layer.borderWidth = 2;
  28 +
  29 + [self.growingButton addTarget:self action:@selector(didTapGrowButton:) forControlEvents:UIControlEventTouchUpInside];
  30 + [self addSubview:self.growingButton];
  31 +
  32 + self.buttonSize = CGSizeMake(100, 100);
  33 + [self setNeedsUpdateConstraints];
  34 +
  35 + return self;
  36 +}
  37 +
  38 +- (void)updateConstraints {
  39 + [super updateConstraints];
  40 +
  41 + [self.growingButton updateConstraints:^(MASConstraintMaker *make) {
  42 + make.center.equalTo(self);
  43 + make.width.equalTo(@(self.buttonSize.width));
  44 + make.height.equalTo(@(self.buttonSize.height));
  45 + }];
  46 +}
  47 +
  48 +- (void)didTapGrowButton:(UIButton *)button {
  49 + self.buttonSize = CGSizeMake(self.buttonSize.width * 1.1, self.buttonSize.height * 1.1);
  50 +
  51 + [self setNeedsUpdateConstraints];
  52 + [self updateConstraintsIfNeeded];
  53 +
  54 + [UIView animateWithDuration:0.4 animations:^{
  55 + [self layoutIfNeeded];
  56 + }];
  57 +}
  58 +
  59 +@end
@@ -104,6 +104,47 @@ it(@"should install constraints", ^{ @@ -104,6 +104,47 @@ it(@"should install constraints", ^{
104 expect([maker install]).to.haveCountOf(2); 104 expect([maker install]).to.haveCountOf(2);
105 }); 105 });
106 106
  107 +it(@"should update constraints", ^{
  108 + MAS_VIEW *newView = MAS_VIEW.new;
  109 + [superview addSubview:newView];
  110 +
  111 + maker.updateExisting = YES;
  112 + maker.left.equalTo(newView).offset(10);
  113 + [maker install];
  114 +
  115 + NSLayoutConstraint *constraint1 = superview.constraints[0];
  116 + expect(constraint1.constant).to.equal(10);
  117 +
  118 + maker.left.equalTo(newView).offset(20);
  119 + [maker install];
  120 +
  121 + expect(superview.constraints).to.haveCountOf(1);
  122 + NSLayoutConstraint *constraint2 = superview.constraints[0];
  123 + expect(constraint2.constant).to.equal(20);
  124 +
  125 + expect(constraint2).to.beIdenticalTo(constraint2);
  126 +});
  127 +
  128 +it(@"should not update constraint", ^{
  129 + MAS_VIEW *newView = MAS_VIEW.new;
  130 + [superview addSubview:newView];
  131 +
  132 + maker.updateExisting = YES;
  133 + maker.left.equalTo(newView).offset(10);
  134 + [maker install];
  135 +
  136 + NSLayoutConstraint *constraint1 = superview.constraints[0];
  137 + expect(constraint1.constant).to.equal(10);
  138 +
  139 + maker.right.equalTo(newView).offset(20);
  140 + [maker install];
  141 +
  142 + expect(superview.constraints).to.haveCountOf(2);
  143 + NSLayoutConstraint *constraint2 = superview.constraints[1];
  144 + expect(constraint1.constant).to.equal(10);
  145 + expect(constraint2.constant).to.equal(20);
  146 +});
  147 +
107 it(@"should create new constraints", ^{ 148 it(@"should create new constraints", ^{
108 expect(maker.left).notTo.beIdenticalTo(maker.left); 149 expect(maker.left).notTo.beIdenticalTo(maker.left);
109 expect(maker.right).notTo.beIdenticalTo(maker.right); 150 expect(maker.right).notTo.beIdenticalTo(maker.right);
@@ -45,6 +45,10 @@ context(@"isEqual", ^{ @@ -45,6 +45,10 @@ context(@"isEqual", ^{
45 layoutAttribute:NSLayoutAttributeRight]; 45 layoutAttribute:NSLayoutAttributeRight];
46 expect([viewAttribute isEqual:otherViewAttribute]).to.equal(NO); 46 expect([viewAttribute isEqual:otherViewAttribute]).to.equal(NO);
47 }); 47 });
  48 +
  49 + it(@"should return NO when non view attribute passed", ^{
  50 + expect([viewAttribute isEqual:NSArray.new]).to.equal(NO);
  51 + });
48 }); 52 });
49 53
50 context(@"hash", ^{ 54 context(@"hash", ^{
@@ -32,10 +32,10 @@ it(@"should display layoutConstraint key", ^{ @@ -32,10 +32,10 @@ it(@"should display layoutConstraint key", ^{
32 MAS_VIEW *newView2 = MAS_VIEW.new; 32 MAS_VIEW *newView2 = MAS_VIEW.new;
33 newView2.mas_key = @"newView2"; 33 newView2.mas_key = @"newView2";
34 34
35 - MASLayoutConstraint *layoutConstraint = [MASLayoutConstraint constraintWithItem:newView1 attribute:NSLayoutAttributeBaseline relatedBy:NSLayoutRelationEqual toItem:newView2 attribute:NSLayoutAttributeTop multiplier:1 constant:300]; 35 + MASLayoutConstraint *layoutConstraint = [MASLayoutConstraint constraintWithItem:newView1 attribute:NSLayoutAttributeBaseline relatedBy:NSLayoutRelationEqual toItem:newView2 attribute:NSLayoutAttributeTop multiplier:2 constant:300];
36 layoutConstraint.mas_key = @"helloConstraint"; 36 layoutConstraint.mas_key = @"helloConstraint";
37 37
38 - NSString *description = [NSString stringWithFormat:@"<MASLayoutConstraint:helloConstraint %@:newView1.baseline == %@:newView2.top + 300>", MAS_VIEW.class, MAS_VIEW.class]; 38 + NSString *description = [NSString stringWithFormat:@"<MASLayoutConstraint:helloConstraint %@:newView1.baseline == %@:newView2.top * 2 + 300>", MAS_VIEW.class, MAS_VIEW.class];
39 expect([layoutConstraint description]).to.equal(description); 39 expect([layoutConstraint description]).to.equal(description);
40 }); 40 });
41 41
@@ -13,7 +13,16 @@ SpecBegin(View_MASAdditions) @@ -13,7 +13,16 @@ SpecBegin(View_MASAdditions)
13 it(@"should set translatesAutoresizingMaskIntoConstraints", ^{ 13 it(@"should set translatesAutoresizingMaskIntoConstraints", ^{
14 MAS_VIEW *newView = MAS_VIEW.new; 14 MAS_VIEW *newView = MAS_VIEW.new;
15 [newView mas_makeConstraints:^(MASConstraintMaker *make) { 15 [newView mas_makeConstraints:^(MASConstraintMaker *make) {
  16 + expect(make.updateExisting).to.beFalsy();
  17 + }];
16 18
  19 + expect(newView.translatesAutoresizingMaskIntoConstraints).to.beFalsy();
  20 +});
  21 +
  22 +it(@"should set updateExisting", ^{
  23 + MAS_VIEW *newView = MAS_VIEW.new;
  24 + [newView mas_updateConstraints:^(MASConstraintMaker *make) {
  25 + expect(make.updateExisting).to.beTruthy();
17 }]; 26 }];
18 27
19 expect(newView.translatesAutoresizingMaskIntoConstraints).to.beFalsy(); 28 expect(newView.translatesAutoresizingMaskIntoConstraints).to.beFalsy();