Merge branch 'develop'

This commit is contained in:
Robert Payne 2015-03-24 11:07:26 +13:00
commit f37b56b7a2
7 changed files with 305 additions and 135 deletions

2
.gitignore vendored
View File

@ -2,3 +2,5 @@ project.xcworkspace
xcuserdata xcuserdata
Examples/ Examples/
.DS_Store .DS_Store
Gemfile
Gemfile.lock

View File

@ -1,6 +1,12 @@
Beta Beta
======= =======
# Next Release
* Re-worked some internal API to allow for future updates
* Added `snp_prepareConstraints -> [Constraint]` which allows pre-building of constraints
* Added a fatal error to `and` when it is used after relation has been set
# 0.0.6 - February 11th, 2015 # 0.0.6 - February 11th, 2015
* Renamed `maker` to `make` in all block APIs * Renamed `maker` to `make` in all block APIs

View File

@ -7,6 +7,8 @@
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
EEAED5481A8F56A500777EF9 /* Snap.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EEBCC9D819CC627D0083B827 /* Snap.framework */; };
EEAED5491A8F56BF00777EF9 /* SnapTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE91728C19CB304E007888CF /* SnapTests.swift */; };
EEBCC9F019CC64F80083B827 /* EdgeInsets.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEBCC9EF19CC64F70083B827 /* EdgeInsets.swift */; }; EEBCC9F019CC64F80083B827 /* EdgeInsets.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEBCC9EF19CC64F70083B827 /* EdgeInsets.swift */; };
EEBCC9F219CC65050083B827 /* View+Snap.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEBCC9F119CC65040083B827 /* View+Snap.swift */; }; EEBCC9F219CC65050083B827 /* View+Snap.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEBCC9F119CC65040083B827 /* View+Snap.swift */; };
EEBCC9F419CC65110083B827 /* ConstraintAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEBCC9F319CC65110083B827 /* ConstraintAttributes.swift */; }; EEBCC9F419CC65110083B827 /* ConstraintAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEBCC9F319CC65110083B827 /* ConstraintAttributes.swift */; };
@ -46,6 +48,7 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
EEAED5481A8F56A500777EF9 /* Snap.framework in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -233,6 +236,7 @@
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
EEAED5491A8F56BF00777EF9 /* SnapTests.swift in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };

View File

@ -31,19 +31,24 @@ import AppKit
* Constraint is a single item that defines all the properties for a single ConstraintMaker chain * Constraint is a single item that defines all the properties for a single ConstraintMaker chain
*/ */
public class Constraint { public class Constraint {
public var left: Constraint { return addConstraint(ConstraintAttributes.Left) } public var left: Constraint { return self.addConstraint(ConstraintAttributes.Left) }
public var top: Constraint { return addConstraint(ConstraintAttributes.Top) } public var top: Constraint { return self.addConstraint(ConstraintAttributes.Top) }
public var right: Constraint { return addConstraint(ConstraintAttributes.Right) } public var right: Constraint { return self.addConstraint(ConstraintAttributes.Right) }
public var bottom: Constraint { return addConstraint(ConstraintAttributes.Bottom) } public var bottom: Constraint { return self.addConstraint(ConstraintAttributes.Bottom) }
public var leading: Constraint { return addConstraint(ConstraintAttributes.Leading) } public var leading: Constraint { return self.addConstraint(ConstraintAttributes.Leading) }
public var trailing: Constraint { return addConstraint(ConstraintAttributes.Trailing) } public var trailing: Constraint { return self.addConstraint(ConstraintAttributes.Trailing) }
public var width: Constraint { return addConstraint(ConstraintAttributes.Width) } public var width: Constraint { return self.addConstraint(ConstraintAttributes.Width) }
public var height: Constraint { return addConstraint(ConstraintAttributes.Height) } public var height: Constraint { return self.addConstraint(ConstraintAttributes.Height) }
public var centerX: Constraint { return addConstraint(ConstraintAttributes.CenterX) } public var centerX: Constraint { return self.addConstraint(ConstraintAttributes.CenterX) }
public var centerY: Constraint { return addConstraint(ConstraintAttributes.CenterY) } public var centerY: Constraint { return self.addConstraint(ConstraintAttributes.CenterY) }
public var baseline: Constraint { return addConstraint(ConstraintAttributes.Baseline) } public var baseline: Constraint { return self.addConstraint(ConstraintAttributes.Baseline) }
public var and: Constraint { return self } public var and: Constraint {
if self.relation != nil {
fatalError("And is semantic only and can only be used before a relation is set.")
}
return self
}
public var with: Constraint { return self } public var with: Constraint { return self }
// MARK: initializer // MARK: initializer
@ -56,115 +61,115 @@ public class Constraint {
// MARK: equalTo // MARK: equalTo
public func equalTo(other: ConstraintItem) -> Constraint { public func equalTo(other: ConstraintItem) -> Constraint {
return constrainTo(other, relation: .Equal) return self.constrainTo(other, relation: .Equal)
} }
public func equalTo(other: View) -> Constraint { public func equalTo(other: View) -> Constraint {
return constrainTo(other, relation: .Equal) return self.constrainTo(other, relation: .Equal)
} }
#if os(iOS) #if os(iOS)
public func equalTo(other: UILayoutSupport) -> Constraint { public func equalTo(other: UILayoutSupport) -> Constraint {
return constrainTo(other, relation: .Equal) return self.constrainTo(other, relation: .Equal)
} }
#endif #endif
public func equalTo(other: Float) -> Constraint { public func equalTo(other: Float) -> Constraint {
return constrainTo(other, relation: .Equal) return self.constrainTo(other, relation: .Equal)
} }
public func equalTo(other: Double) -> Constraint { public func equalTo(other: Double) -> Constraint {
return constrainTo(Float(other), relation: .Equal) return self.constrainTo(Float(other), relation: .Equal)
} }
public func equalTo(other: CGFloat) -> Constraint { public func equalTo(other: CGFloat) -> Constraint {
return constrainTo(Float(other), relation: .Equal) return self.constrainTo(Float(other), relation: .Equal)
} }
public func equalTo(other: Int) -> Constraint { public func equalTo(other: Int) -> Constraint {
return constrainTo(Float(other), relation: .Equal) return self.constrainTo(Float(other), relation: .Equal)
} }
public func equalTo(other: UInt) -> Constraint { public func equalTo(other: UInt) -> Constraint {
return constrainTo(Float(other), relation: .Equal) return self.constrainTo(Float(other), relation: .Equal)
} }
public func equalTo(other: CGSize) -> Constraint { public func equalTo(other: CGSize) -> Constraint {
return constrainTo(other, relation: .Equal) return self.constrainTo(other, relation: .Equal)
} }
public func equalTo(other: CGPoint) -> Constraint { public func equalTo(other: CGPoint) -> Constraint {
return constrainTo(other, relation: .Equal) return self.constrainTo(other, relation: .Equal)
} }
public func equalTo(other: EdgeInsets) -> Constraint { public func equalTo(other: EdgeInsets) -> Constraint {
return constrainTo(other, relation: .Equal) return self.constrainTo(other, relation: .Equal)
} }
// MARK: lessThanOrEqualTo // MARK: lessThanOrEqualTo
public func lessThanOrEqualTo(other: ConstraintItem) -> Constraint { public func lessThanOrEqualTo(other: ConstraintItem) -> Constraint {
return constrainTo(other, relation: .LessThanOrEqualTo) return self.constrainTo(other, relation: .LessThanOrEqualTo)
} }
public func lessThanOrEqualTo(other: View) -> Constraint { public func lessThanOrEqualTo(other: View) -> Constraint {
return constrainTo(other, relation: .LessThanOrEqualTo) return self.constrainTo(other, relation: .LessThanOrEqualTo)
} }
#if os(iOS) #if os(iOS)
public func lessThanOrEqualTo(other: UILayoutSupport) -> Constraint { public func lessThanOrEqualTo(other: UILayoutSupport) -> Constraint {
return constrainTo(other, relation: .LessThanOrEqualTo) return self.constrainTo(other, relation: .LessThanOrEqualTo)
} }
#endif #endif
public func lessThanOrEqualTo(other: Float) -> Constraint { public func lessThanOrEqualTo(other: Float) -> Constraint {
return constrainTo(other, relation: .LessThanOrEqualTo) return self.constrainTo(other, relation: .LessThanOrEqualTo)
} }
public func lessThanOrEqualTo(other: Double) -> Constraint { public func lessThanOrEqualTo(other: Double) -> Constraint {
return constrainTo(Float(other), relation: .LessThanOrEqualTo) return self.constrainTo(Float(other), relation: .LessThanOrEqualTo)
} }
public func lessThanOrEqualTo(other: CGFloat) -> Constraint { public func lessThanOrEqualTo(other: CGFloat) -> Constraint {
return constrainTo(Float(other), relation: .LessThanOrEqualTo) return self.constrainTo(Float(other), relation: .LessThanOrEqualTo)
} }
public func lessThanOrEqualTo(other: Int) -> Constraint { public func lessThanOrEqualTo(other: Int) -> Constraint {
return constrainTo(Float(other), relation: .LessThanOrEqualTo) return self.constrainTo(Float(other), relation: .LessThanOrEqualTo)
} }
public func lessThanOrEqualTo(other: UInt) -> Constraint { public func lessThanOrEqualTo(other: UInt) -> Constraint {
return constrainTo(Float(other), relation: .LessThanOrEqualTo) return self.constrainTo(Float(other), relation: .LessThanOrEqualTo)
} }
public func lessThanOrEqualTo(other: CGSize) -> Constraint { public func lessThanOrEqualTo(other: CGSize) -> Constraint {
return constrainTo(other, relation: .LessThanOrEqualTo) return self.constrainTo(other, relation: .LessThanOrEqualTo)
} }
public func lessThanOrEqualTo(other: CGPoint) -> Constraint { public func lessThanOrEqualTo(other: CGPoint) -> Constraint {
return constrainTo(other, relation: .LessThanOrEqualTo) return self.constrainTo(other, relation: .LessThanOrEqualTo)
} }
public func lessThanOrEqualTo(other: EdgeInsets) -> Constraint { public func lessThanOrEqualTo(other: EdgeInsets) -> Constraint {
return constrainTo(other, relation: .LessThanOrEqualTo) return self.constrainTo(other, relation: .LessThanOrEqualTo)
} }
// MARK: greaterThanOrEqualTo // MARK: greaterThanOrEqualTo
public func greaterThanOrEqualTo(other: ConstraintItem) -> Constraint { public func greaterThanOrEqualTo(other: ConstraintItem) -> Constraint {
return constrainTo(other, relation: .GreaterThanOrEqualTo) return self.constrainTo(other, relation: .GreaterThanOrEqualTo)
} }
public func greaterThanOrEqualTo(other: View) -> Constraint { public func greaterThanOrEqualTo(other: View) -> Constraint {
return constrainTo(other, relation: .GreaterThanOrEqualTo) return self.constrainTo(other, relation: .GreaterThanOrEqualTo)
} }
#if os(iOS) #if os(iOS)
public func greaterThanOrEqualTo(other: UILayoutSupport) -> Constraint { public func greaterThanOrEqualTo(other: UILayoutSupport) -> Constraint {
return constrainTo(other, relation: .GreaterThanOrEqualTo) return self.constrainTo(other, relation: .GreaterThanOrEqualTo)
} }
#endif #endif
public func greaterThanOrEqualTo(other: Float) -> Constraint { public func greaterThanOrEqualTo(other: Float) -> Constraint {
return constrainTo(other, relation: .GreaterThanOrEqualTo) return self.constrainTo(other, relation: .GreaterThanOrEqualTo)
} }
public func greaterThanOrEqualTo(other: Double) -> Constraint { public func greaterThanOrEqualTo(other: Double) -> Constraint {
return constrainTo(Float(other), relation: .GreaterThanOrEqualTo) return self.constrainTo(Float(other), relation: .GreaterThanOrEqualTo)
} }
public func greaterThanOrEqualTo(other: CGFloat) -> Constraint { public func greaterThanOrEqualTo(other: CGFloat) -> Constraint {
return constrainTo(Float(other), relation: .GreaterThanOrEqualTo) return self.constrainTo(Float(other), relation: .GreaterThanOrEqualTo)
} }
public func greaterThanOrEqualTo(other: Int) -> Constraint { public func greaterThanOrEqualTo(other: Int) -> Constraint {
return constrainTo(Float(other), relation: .GreaterThanOrEqualTo) return self.constrainTo(Float(other), relation: .GreaterThanOrEqualTo)
} }
public func greaterThanOrEqualTo(other: UInt) -> Constraint { public func greaterThanOrEqualTo(other: UInt) -> Constraint {
return constrainTo(Float(other), relation: .GreaterThanOrEqualTo) return self.constrainTo(Float(other), relation: .GreaterThanOrEqualTo)
} }
public func greaterThanOrEqualTo(other: CGSize) -> Constraint { public func greaterThanOrEqualTo(other: CGSize) -> Constraint {
return constrainTo(other, relation: .GreaterThanOrEqualTo) return self.constrainTo(other, relation: .GreaterThanOrEqualTo)
} }
public func greaterThanOrEqualTo(other: CGPoint) -> Constraint { public func greaterThanOrEqualTo(other: CGPoint) -> Constraint {
return constrainTo(other, relation: .GreaterThanOrEqualTo) return self.constrainTo(other, relation: .GreaterThanOrEqualTo)
} }
public func greaterThanOrEqualTo(other: EdgeInsets) -> Constraint { public func greaterThanOrEqualTo(other: EdgeInsets) -> Constraint {
return constrainTo(other, relation: .GreaterThanOrEqualTo) return self.constrainTo(other, relation: .GreaterThanOrEqualTo)
} }
// MARK: multiplier // MARK: multiplier
@ -282,11 +287,6 @@ public class Constraint {
// MARK: internal // MARK: internal
internal func installOnView(updateExisting: Bool = false) -> Array<LayoutConstraint> { internal func installOnView(updateExisting: Bool = false) -> Array<LayoutConstraint> {
if self.installedOnView != nil {
NSException(name: "Cannot Install Constraint", reason: "Already installed", userInfo: nil).raise()
return []
}
var installOnView: View? = nil var installOnView: View? = nil
if self.toItem.view != nil { if self.toItem.view != nil {
installOnView = Constraint.closestCommonSuperviewFromView(self.fromItem.view, toView: self.toItem.view) installOnView = Constraint.closestCommonSuperviewFromView(self.fromItem.view, toView: self.toItem.view)
@ -301,14 +301,22 @@ public class Constraint {
installOnView = self.fromItem.view installOnView = self.fromItem.view
} }
if installedOnView == nil { if installOnView == nil {
NSException(name: "Cannot Install Constraint", reason: "Missing superview", userInfo: nil).raise() NSException(name: "Cannot Install Constraint", reason: "Missing superview", userInfo: nil).raise()
return [] return []
} }
} }
} }
var layoutConstraints: Array<LayoutConstraint> = [] if self.installedOnView != nil {
if self.installedOnView != installOnView {
NSException(name: "Cannot Install Constraint", reason: "Already installed on different view.", userInfo: nil).raise()
return []
}
return self.installedLayoutConstraints?.allObjects as Array<LayoutConstraint>
}
var newLayoutConstraints = Array<LayoutConstraint>()
let layoutFromAttributes = self.fromItem.attributes.layoutAttributes let layoutFromAttributes = self.fromItem.attributes.layoutAttributes
let layoutToAttributes = self.toItem.attributes.layoutAttributes let layoutToAttributes = self.toItem.attributes.layoutAttributes
@ -348,7 +356,7 @@ public class Constraint {
// set constraint // set constraint
layoutConstraint.constraint = self layoutConstraint.constraint = self
layoutConstraints.append(layoutConstraint) newLayoutConstraints.append(layoutConstraint)
} }
// special logic for updating // special logic for updating
@ -356,11 +364,11 @@ public class Constraint {
// get existing constraints for this view // get existing constraints for this view
let existingLayoutConstraints = reverse(layoutFrom!.snp_installedLayoutConstraints) let existingLayoutConstraints = reverse(layoutFrom!.snp_installedLayoutConstraints)
// array that will contain only new layout constraints // array that will contain only new layout constraints to keep
var newLayoutConstraints = Array<LayoutConstraint>() var newLayoutConstraintsToKeep = Array<LayoutConstraint>()
// begin looping // begin looping
for layoutConstraint in layoutConstraints { for layoutConstraint in newLayoutConstraints {
// layout constraint that should be updated // layout constraint that should be updated
var updateLayoutConstraint: LayoutConstraint? = nil var updateLayoutConstraint: LayoutConstraint? = nil
@ -376,34 +384,45 @@ public class Constraint {
if updateLayoutConstraint != nil { if updateLayoutConstraint != nil {
updateLayoutConstraint!.constant = layoutConstraint.constant updateLayoutConstraint!.constant = layoutConstraint.constant
} }
// otherwise add this layout constraint to new list // otherwise add this layout constraint to new keep list
else { else {
newLayoutConstraints.append(layoutConstraint) newLayoutConstraintsToKeep.append(layoutConstraint)
} }
} }
// set constraints to only new ones // set constraints to only new ones
layoutConstraints = newLayoutConstraints newLayoutConstraints = newLayoutConstraintsToKeep
} }
// add constraints // add constraints
installOnView!.addConstraints(layoutConstraints) installOnView!.addConstraints(newLayoutConstraints)
// store which view this constraint was installed on
self.installedOnView = installOnView self.installedOnView = installOnView
// store which layout constraints are installed for this constraint
self.installedLayoutConstraints = NSHashTable.weakObjectsHashTable() self.installedLayoutConstraints = NSHashTable.weakObjectsHashTable()
for layoutConstraint in layoutConstraints { for layoutConstraint in newLayoutConstraints {
self.installedLayoutConstraints!.addObject(layoutConstraint) self.installedLayoutConstraints!.addObject(layoutConstraint)
} }
return layoutConstraints // store the layout constraints against the installed on view
var layoutConstraints = Array<LayoutConstraint>(layoutFrom!.snp_installedLayoutConstraints)
layoutConstraints += newLayoutConstraints
layoutFrom!.snp_installedLayoutConstraints = layoutConstraints
// return the new constraints
return newLayoutConstraints
} }
internal func uninstallFromView() { internal func uninstallFromView() {
if let view = self.installedOnView { if let view = self.installedOnView {
// remove all installed layout constraints // remove all installed layout constraints
var layoutConstraintsToRemove = Array<LayoutConstraint>() var layoutConstraintsToRemove = Array<LayoutConstraint>()
if let installedLayoutConstraints = self.installedLayoutConstraints?.allObjects as? Array<LayoutConstraint> { if let allObjects = self.installedLayoutConstraints?.allObjects {
layoutConstraintsToRemove += installedLayoutConstraints if let installedLayoutConstraints = allObjects as? Array<LayoutConstraint> {
layoutConstraintsToRemove += installedLayoutConstraints
}
} }
if layoutConstraintsToRemove.count > 0 { if layoutConstraintsToRemove.count > 0 {
@ -490,19 +509,27 @@ public class Constraint {
} }
private class func closestCommonSuperviewFromView(fromView: View?, toView: View?) -> View? { private class func closestCommonSuperviewFromView(fromView: View?, toView: View?) -> View? {
var closestCommonSuperview: View? var views = NSMutableSet()
var secondViewSuperview: View? = toView var fromView = fromView
while closestCommonSuperview == nil && secondViewSuperview != nil { var toView = toView
var firstViewSuperview = fromView do {
while closestCommonSuperview == nil && firstViewSuperview != nil { if let view = toView {
if secondViewSuperview == firstViewSuperview { if views.containsObject(view) {
closestCommonSuperview = secondViewSuperview return view
} }
firstViewSuperview = firstViewSuperview?.superview views.addObject(view)
toView = view.superview
} }
secondViewSuperview = secondViewSuperview?.superview if let view = fromView {
} if views.containsObject(view) {
return closestCommonSuperview return view
}
views.addObject(view)
fromView = view.superview
}
} while (fromView != nil || toView != nil)
return nil
} }
} }

View File

@ -31,21 +31,21 @@ import AppKit
* ConstraintMaker is the maker in snap that gets all constraints kickstarted * ConstraintMaker is the maker in snap that gets all constraints kickstarted
*/ */
public class ConstraintMaker { public class ConstraintMaker {
public var left: Constraint { return addConstraint(ConstraintAttributes.Left) } public var left: Constraint { return self.addConstraint(ConstraintAttributes.Left) }
public var top: Constraint { return addConstraint(ConstraintAttributes.Top) } public var top: Constraint { return self.addConstraint(ConstraintAttributes.Top) }
public var right: Constraint { return addConstraint(ConstraintAttributes.Right) } public var right: Constraint { return self.addConstraint(ConstraintAttributes.Right) }
public var bottom: Constraint { return addConstraint(ConstraintAttributes.Bottom) } public var bottom: Constraint { return self.addConstraint(ConstraintAttributes.Bottom) }
public var leading: Constraint { return addConstraint(ConstraintAttributes.Leading) } public var leading: Constraint { return self.addConstraint(ConstraintAttributes.Leading) }
public var trailing: Constraint { return addConstraint(ConstraintAttributes.Trailing) } public var trailing: Constraint { return self.addConstraint(ConstraintAttributes.Trailing) }
public var width: Constraint { return addConstraint(ConstraintAttributes.Width) } public var width: Constraint { return self.addConstraint(ConstraintAttributes.Width) }
public var height: Constraint { return addConstraint(ConstraintAttributes.Height) } public var height: Constraint { return self.addConstraint(ConstraintAttributes.Height) }
public var centerX: Constraint { return addConstraint(ConstraintAttributes.CenterX) } public var centerX: Constraint { return self.addConstraint(ConstraintAttributes.CenterX) }
public var centerY: Constraint { return addConstraint(ConstraintAttributes.CenterY) } public var centerY: Constraint { return self.addConstraint(ConstraintAttributes.CenterY) }
public var baseline: Constraint { return addConstraint(ConstraintAttributes.Baseline) } public var baseline: Constraint { return self.addConstraint(ConstraintAttributes.Baseline) }
public var edges: Constraint { return addConstraint(ConstraintAttributes.Edges) } public var edges: Constraint { return self.addConstraint(ConstraintAttributes.Edges) }
public var size: Constraint { return addConstraint(ConstraintAttributes.Size) } public var size: Constraint { return self.addConstraint(ConstraintAttributes.Size) }
public var center: Constraint { return addConstraint(ConstraintAttributes.Center) } public var center: Constraint { return self.addConstraint(ConstraintAttributes.Center) }
init(view: View) { init(view: View) {
self.view = view self.view = view
@ -61,24 +61,26 @@ public class ConstraintMaker {
return constraint return constraint
} }
internal class func makeConstraints(view: View, block: (make: ConstraintMaker) -> ()) { internal class func prepareConstraints(view: View, block: (make: ConstraintMaker) -> Void) -> Array<Constraint> {
#if os(iOS)
view.setTranslatesAutoresizingMaskIntoConstraints(false)
#else
view.translatesAutoresizingMaskIntoConstraints = false
#endif
let maker = ConstraintMaker(view: view) let maker = ConstraintMaker(view: view)
block(make: maker) block(make: maker)
return maker.constraints
var layoutConstraints = view.snp_installedLayoutConstraints
for constraint in maker.constraints {
layoutConstraints += constraint.install()
}
view.snp_installedLayoutConstraints = layoutConstraints
} }
internal class func remakeConstraints(view: View, block: (make: ConstraintMaker) -> ()) { internal class func makeConstraints(view: View, block: (make: ConstraintMaker) -> Void) {
#if os(iOS)
view.setTranslatesAutoresizingMaskIntoConstraints(false)
#else
view.translatesAutoresizingMaskIntoConstraints = false
#endif
let maker = ConstraintMaker(view: view)
block(make: maker)
for constraint in maker.constraints {
constraint.installOnView(updateExisting: false)
}
}
internal class func remakeConstraints(view: View, block: (make: ConstraintMaker) -> Void) {
#if os(iOS) #if os(iOS)
view.setTranslatesAutoresizingMaskIntoConstraints(false) view.setTranslatesAutoresizingMaskIntoConstraints(false)
#else #else
@ -87,20 +89,17 @@ public class ConstraintMaker {
let maker = ConstraintMaker(view: view) let maker = ConstraintMaker(view: view)
block(make: maker) block(make: maker)
var layoutConstraints: Array<LayoutConstraint> = view.snp_installedLayoutConstraints var layoutConstraints = Array<LayoutConstraint>(view.snp_installedLayoutConstraints)
for existingLayoutConstraint in layoutConstraints { for existingLayoutConstraint in layoutConstraints {
existingLayoutConstraint.constraint?.uninstall() existingLayoutConstraint.constraint?.uninstallFromView()
} }
layoutConstraints = []
for constraint in maker.constraints { for constraint in maker.constraints {
layoutConstraints += constraint.install() constraint.installOnView(updateExisting: false)
} }
view.snp_installedLayoutConstraints = layoutConstraints
} }
internal class func updateConstraints(view: View, block: (make: ConstraintMaker) -> ()) { internal class func updateConstraints(view: View, block: (make: ConstraintMaker) -> Void) {
#if os(iOS) #if os(iOS)
view.setTranslatesAutoresizingMaskIntoConstraints(false) view.setTranslatesAutoresizingMaskIntoConstraints(false)
#else #else
@ -109,19 +108,15 @@ public class ConstraintMaker {
let maker = ConstraintMaker(view: view) let maker = ConstraintMaker(view: view)
block(make: maker) block(make: maker)
var layoutConstraints = view.snp_installedLayoutConstraints
for constraint in maker.constraints { for constraint in maker.constraints {
layoutConstraints += constraint.installOnView(updateExisting: true) constraint.installOnView(updateExisting: true)
} }
view.snp_installedLayoutConstraints = layoutConstraints
} }
internal class func removeConstraints(view: View) { internal class func removeConstraints(view: View) {
for existingLayoutConstraint in view.snp_installedLayoutConstraints { let existingLayoutConstraints = Array<LayoutConstraint>(view.snp_installedLayoutConstraints)
existingLayoutConstraint.constraint?.uninstall() for existingLayoutConstraint in existingLayoutConstraints {
existingLayoutConstraint.constraint?.uninstallFromView()
} }
view.snp_installedLayoutConstraints = []
} }
} }

View File

@ -68,15 +68,19 @@ public extension View {
public var snp_centerWithinMargins: ConstraintItem { return ConstraintItem(object: self, attributes: ConstraintAttributes.CenterWithinMargins) } public var snp_centerWithinMargins: ConstraintItem { return ConstraintItem(object: self, attributes: ConstraintAttributes.CenterWithinMargins) }
#endif #endif
public func snp_makeConstraints(block: (make: ConstraintMaker) -> ()) { public func snp_prepareConstraints(block: (make: ConstraintMaker) -> Void) -> Array<Constraint> {
return ConstraintMaker.prepareConstraints(self, block: block)
}
public func snp_makeConstraints(block: (make: ConstraintMaker) -> Void) {
ConstraintMaker.makeConstraints(self, block: block) ConstraintMaker.makeConstraints(self, block: block)
} }
public func snp_updateConstraints(block: (make: ConstraintMaker) -> ()) { public func snp_updateConstraints(block: (make: ConstraintMaker) -> Void) {
ConstraintMaker.updateConstraints(self, block: block) ConstraintMaker.updateConstraints(self, block: block)
} }
public func snp_remakeConstraints(block: (make: ConstraintMaker) -> ()) { public func snp_remakeConstraints(block: (make: ConstraintMaker) -> Void) {
ConstraintMaker.remakeConstraints(self, block: block) ConstraintMaker.remakeConstraints(self, block: block)
} }
@ -88,11 +92,10 @@ public extension View {
internal var snp_installedLayoutConstraints: Array<LayoutConstraint> { internal var snp_installedLayoutConstraints: Array<LayoutConstraint> {
get { get {
var constraints = objc_getAssociatedObject(self, &installedLayoutConstraintsKey) as? Array<LayoutConstraint> if let constraints = objc_getAssociatedObject(self, &installedLayoutConstraintsKey) as? Array<LayoutConstraint> {
if constraints != nil { return constraints
return constraints!
} }
return [] return Array<LayoutConstraint>()
} }
set { set {
objc_setAssociatedObject(self, &installedLayoutConstraintsKey, newValue, UInt(OBJC_ASSOCIATION_RETAIN_NONATOMIC)) objc_setAssociatedObject(self, &installedLayoutConstraintsKey, newValue, UInt(OBJC_ASSOCIATION_RETAIN_NONATOMIC))

View File

@ -8,9 +8,12 @@
import UIKit import UIKit
import XCTest import XCTest
import Snap
class SnapTests: XCTestCase { class SnapTests: XCTestCase {
let container = UIView()
override func setUp() { override func setUp() {
super.setUp() super.setUp()
// Put setup code here. This method is called before the invocation of each test method in the class. // Put setup code here. This method is called before the invocation of each test method in the class.
@ -21,16 +24,146 @@ class SnapTests: XCTestCase {
super.tearDown() super.tearDown()
} }
func testExample() { func testMakeConstraints() {
// This is an example of a functional test case. let v1 = UIView()
XCTAssert(true, "Pass") let v2 = UIView()
self.container.addSubview(v1)
self.container.addSubview(v2)
v1.snp_makeConstraints { (make) -> Void in
make.top.equalTo(v2.snp_top).offset(50)
make.left.equalTo(v2.snp_top).offset(50)
return
}
XCTAssertEqual(self.container.constraints().count, 2, "Should have 2 constraints installed")
v2.snp_makeConstraints { (make) -> Void in
make.edges.equalTo(v1)
return
}
XCTAssertEqual(self.container.constraints().count, 6, "Should have 6 constraints installed")
} }
func testPerformanceExample() { func testUpdateConstraints() {
// This is an example of a performance test case. let v1 = UIView()
self.measureBlock() { let v2 = UIView()
// Put the code you want to measure the time of here. self.container.addSubview(v1)
self.container.addSubview(v2)
v1.snp_makeConstraints { (make) -> Void in
make.top.equalTo(v2.snp_top).offset(50)
make.left.equalTo(v2.snp_top).offset(50)
return
} }
XCTAssertEqual(self.container.constraints().count, 2, "Should have 2 constraints installed")
v1.snp_updateConstraints { (make) -> Void in
make.top.equalTo(v2.snp_top).offset(15)
return
}
XCTAssertEqual(self.container.constraints().count, 2, "Should still have 2 constraints installed")
}
func testRemakeConstraints() {
let v1 = UIView()
let v2 = UIView()
self.container.addSubview(v1)
self.container.addSubview(v2)
v1.snp_makeConstraints { (make) -> Void in
make.top.equalTo(v2.snp_top).offset(50)
make.left.equalTo(v2.snp_top).offset(50)
return
}
XCTAssertEqual(self.container.constraints().count, 2, "Should have 2 constraints installed")
v1.snp_remakeConstraints { (make) -> Void in
make.edges.equalTo(v2)
return
}
XCTAssertEqual(self.container.constraints().count, 4, "Should have 4 constraints installed")
}
func testRemoveConstraints() {
let v1 = UIView()
let v2 = UIView()
self.container.addSubview(v1)
self.container.addSubview(v2)
v1.snp_makeConstraints { (make) -> Void in
make.top.equalTo(v2.snp_top).offset(50)
make.left.equalTo(v2.snp_top).offset(50)
return
}
XCTAssertEqual(self.container.constraints().count, 2, "Should have 2 constraints installed")
v1.snp_removeConstraints()
XCTAssertEqual(self.container.constraints().count, 0, "Should have 0 constraints installed")
}
func testPrepareConstraints() {
let v1 = UIView()
let v2 = UIView()
self.container.addSubview(v1)
self.container.addSubview(v2)
let constraints = v1.snp_prepareConstraints { (make) -> Void in
make.edges.equalTo(v2)
return
}
XCTAssertEqual(self.container.constraints().count, 0, "Should have 0 constraints installed")
for constraint in constraints {
constraint.install()
}
XCTAssertEqual(self.container.constraints().count, 4, "Should have 4 constraints installed")
for constraint in constraints {
constraint.uninstall()
}
XCTAssertEqual(self.container.constraints().count, 0, "Should have 0 constraints installed")
}
func testReinstallConstraints() {
let v1 = UIView()
let v2 = UIView()
self.container.addSubview(v1)
self.container.addSubview(v2)
let constraints = v1.snp_prepareConstraints { (make) -> Void in
make.edges.equalTo(v2)
return
}
XCTAssertEqual(self.container.constraints().count, 0, "Should have 0 constraints installed")
for constraint in constraints {
constraint.install()
}
XCTAssertEqual(self.container.constraints().count, 4, "Should have 4 constraints installed")
for constraint in constraints {
constraint.install()
}
XCTAssertEqual(self.container.constraints().count, 4, "Should have 0 constraints installed")
} }
} }