From 104ce8895c69f88f1de9e0f968cee204ef063acf Mon Sep 17 00:00:00 2001 From: Akiva Leffert Date: Mon, 12 Oct 2015 01:53:46 -0400 Subject: [PATCH] Convert protocol hierarchy to class hierarchy This has no value unto itself, but is necessary for adding default arguments to the ConstraintDescriptionRelatable methods, which we'll need to instrument in source locations. --- Source/ConstraintDescription.swift | 331 +++++++++++++++++------------ Source/ConstraintMaker.swift | 4 +- 2 files changed, 193 insertions(+), 142 deletions(-) diff --git a/Source/ConstraintDescription.swift b/Source/ConstraintDescription.swift index f3a137c..90201d1 100644 --- a/Source/ConstraintDescription.swift +++ b/Source/ConstraintDescription.swift @@ -106,138 +106,231 @@ extension View : RelationTarget { } } +extension ConstraintItem : RelationTarget { + public var constraintItem : ConstraintItem { + return self + } +} + /** Used to expose the final API of a `ConstraintDescription` which allows getting a constraint from it */ -public protocol ConstraintDescriptionFinalizable: class { +public class ConstraintDescriptionFinalizable { - var constraint: Constraint { get } + private let backing : ConstraintDescription + internal init(_ backing : ConstraintDescription) { + self.backing = backing + } + + public var constraint: Constraint { + return backing.constraint + } } /** Used to expose priority APIs */ -public protocol ConstraintDescriptionPriortizable: ConstraintDescriptionFinalizable { +public class ConstraintDescriptionPriortizable: ConstraintDescriptionFinalizable { - func priority(priority: FloatConvertible) -> ConstraintDescriptionFinalizable - func priorityRequired() -> ConstraintDescriptionFinalizable - func priorityHigh() -> ConstraintDescriptionFinalizable - func priorityMedium() -> ConstraintDescriptionFinalizable - func priorityLow() -> ConstraintDescriptionFinalizable + public func priority(priority: FloatConvertible) -> ConstraintDescriptionFinalizable { + return ConstraintDescriptionFinalizable(self.backing.priority(priority)) + } + + public func priorityRequired() -> ConstraintDescriptionFinalizable { + return ConstraintDescriptionFinalizable(self.backing.priorityRequired()) + } + public func priorityHigh() -> ConstraintDescriptionFinalizable { + return ConstraintDescriptionFinalizable(self.backing.priorityHigh()) + } + public func priorityMedium() -> ConstraintDescriptionFinalizable { + return ConstraintDescriptionFinalizable(self.backing.priorityMedium()) + } + public func priorityLow() -> ConstraintDescriptionFinalizable { + return ConstraintDescriptionFinalizable(self.backing.priorityLow()) + } } /** Used to expose multiplier & constant APIs */ -public protocol ConstraintDescriptionEditable: ConstraintDescriptionPriortizable { +public class ConstraintDescriptionEditable: ConstraintDescriptionPriortizable { - func multipliedBy(amount: FloatConvertible) -> ConstraintDescriptionEditable + public func multipliedBy(amount: FloatConvertible) -> ConstraintDescriptionEditable { + return ConstraintDescriptionEditable(self.backing.multipliedBy(amount)) + } - func dividedBy(amount: FloatConvertible) -> ConstraintDescriptionEditable - - func offset(amount: FloatConvertible) -> ConstraintDescriptionEditable - func offset(amount: CGPoint) -> ConstraintDescriptionEditable - func offset(amount: CGSize) -> ConstraintDescriptionEditable - func offset(amount: EdgeInsets) -> ConstraintDescriptionEditable + public func dividedBy(amount: FloatConvertible) -> ConstraintDescriptionEditable { + return self.multipliedBy(1 / amount.floatValue) + } - func inset(amount: FloatConvertible) -> ConstraintDescriptionEditable - func inset(amount: EdgeInsets) -> ConstraintDescriptionEditable + public func offset(amount : FloatConvertible) -> ConstraintDescriptionEditable { + return ConstraintDescriptionEditable(self.backing.offset(amount)) + } + public func offset(amount: CGPoint) -> ConstraintDescriptionEditable { + return ConstraintDescriptionEditable(self.backing.offset(amount)) + } + public func offset(amount: CGSize) -> ConstraintDescriptionEditable { + return ConstraintDescriptionEditable(self.backing.offset(amount)) + } + public func offset(amount: EdgeInsets) -> ConstraintDescriptionEditable { + return ConstraintDescriptionEditable(self.backing.offset(amount)) + } + + public func inset(amount: FloatConvertible) -> ConstraintDescriptionEditable { + return ConstraintDescriptionEditable(self.backing.inset(amount)) + } + public func inset(amount: EdgeInsets) -> ConstraintDescriptionEditable { + return ConstraintDescriptionEditable(self.backing.inset(amount)) + } } /** Used to expose relation APIs */ -public protocol ConstraintDescriptionRelatable: class { +public class ConstraintDescriptionRelatable { + + private let backing : ConstraintDescription - func equalTo(other: ConstraintItem) -> ConstraintDescriptionEditable - func equalTo(other: RelationTarget) -> ConstraintDescriptionEditable - @available(iOS 7.0, *) - func equalTo(other: LayoutSupport) -> ConstraintDescriptionEditable + init(_ backing : ConstraintDescription) { + self.backing = backing + } - func lessThanOrEqualTo(other: ConstraintItem) -> ConstraintDescriptionEditable - func lessThanOrEqualTo(other: RelationTarget) -> ConstraintDescriptionEditable - @available(iOS 7.0, *) - func lessThanOrEqualTo(other: LayoutSupport) -> ConstraintDescriptionEditable + + public func equalTo(other: RelationTarget) -> ConstraintDescriptionEditable { + return ConstraintDescriptionEditable(self.backing.constrainTo(other, relation : .Equal)) + } + public func equalTo(other: LayoutSupport) -> ConstraintDescriptionEditable { + return ConstraintDescriptionEditable(self.backing.constrainTo(other, relation : .Equal)) + } - func greaterThanOrEqualTo(other: ConstraintItem) -> ConstraintDescriptionEditable - func greaterThanOrEqualTo(other: RelationTarget) -> ConstraintDescriptionEditable - @available(iOS 7.0, *) - func greaterThanOrEqualTo(other: LayoutSupport) -> ConstraintDescriptionEditable + public func lessThanOrEqualTo(other: RelationTarget) -> ConstraintDescriptionEditable { + return ConstraintDescriptionEditable(self.backing.constrainTo(other, relation : .LessThanOrEqualTo)) + } + public func lessThanOrEqualTo(other: LayoutSupport) -> ConstraintDescriptionEditable { + return ConstraintDescriptionEditable(self.backing.constrainTo(other, relation : .LessThanOrEqualTo)) + } + + public func greaterThanOrEqualTo(other: RelationTarget) -> ConstraintDescriptionEditable { + return ConstraintDescriptionEditable(self.backing.constrainTo(other, relation : .GreaterThanOrEqualTo)) + } + public func greaterThanOrEqualTo(other: LayoutSupport) -> ConstraintDescriptionEditable { + return ConstraintDescriptionEditable(self.backing.constrainTo(other, relation : .GreaterThanOrEqualTo)) + } } /** Used to expose chaining APIs */ -public protocol ConstraintDescriptionExtendable: ConstraintDescriptionRelatable { +public class ConstraintDescriptionExtendable: ConstraintDescriptionRelatable { - var left: ConstraintDescriptionExtendable { get } - var top: ConstraintDescriptionExtendable { get } - var bottom: ConstraintDescriptionExtendable { get } - var right: ConstraintDescriptionExtendable { get } - var leading: ConstraintDescriptionExtendable { get } - var trailing: ConstraintDescriptionExtendable { get } - var width: ConstraintDescriptionExtendable { get } - var height: ConstraintDescriptionExtendable { get } - var centerX: ConstraintDescriptionExtendable { get } - var centerY: ConstraintDescriptionExtendable { get } - var baseline: ConstraintDescriptionExtendable { get } + public var left: ConstraintDescriptionExtendable { + return ConstraintDescriptionExtendable(self.backing.left) + } + public var top: ConstraintDescriptionExtendable { + return ConstraintDescriptionExtendable(self.backing.top) + } + public var bottom: ConstraintDescriptionExtendable { + return ConstraintDescriptionExtendable(self.backing.bottom) + } + public var right: ConstraintDescriptionExtendable { + return ConstraintDescriptionExtendable(self.backing.right) + } + public var leading: ConstraintDescriptionExtendable { + return ConstraintDescriptionExtendable(self.backing.leading) + } + public var trailing: ConstraintDescriptionExtendable { + return ConstraintDescriptionExtendable(self.backing.trailing) + } + public var width: ConstraintDescriptionExtendable { + return ConstraintDescriptionExtendable(self.backing.width) + } + public var height: ConstraintDescriptionExtendable { + return ConstraintDescriptionExtendable(self.backing.height) + } + public var centerX: ConstraintDescriptionExtendable { + return ConstraintDescriptionExtendable(self.backing.centerX) + } + public var centerY: ConstraintDescriptionExtendable { + return ConstraintDescriptionExtendable(self.backing.centerY) + } + public var baseline: ConstraintDescriptionExtendable { + return ConstraintDescriptionExtendable(self.backing.baseline) + } @available(iOS 8.0, *) - var firstBaseline: ConstraintDescriptionExtendable { get } + public var firstBaseline: ConstraintDescriptionExtendable { + return ConstraintDescriptionExtendable(self.backing.firstBaseline) + } @available(iOS 8.0, *) - var leftMargin: ConstraintDescriptionExtendable { get } + public var leftMargin: ConstraintDescriptionExtendable { + return ConstraintDescriptionExtendable(self.backing.leftMargin) + } @available(iOS 8.0, *) - var rightMargin: ConstraintDescriptionExtendable { get } + public var rightMargin: ConstraintDescriptionExtendable { + return ConstraintDescriptionExtendable(self.backing.rightMargin) + } @available(iOS 8.0, *) - var topMargin: ConstraintDescriptionExtendable { get } + public var topMargin: ConstraintDescriptionExtendable { + return ConstraintDescriptionExtendable(self.backing.topMargin) + } @available(iOS 8.0, *) - var bottomMargin: ConstraintDescriptionExtendable { get } + public var bottomMargin: ConstraintDescriptionExtendable { + return ConstraintDescriptionExtendable(self.backing.bottomMargin) + } @available(iOS 8.0, *) - var leadingMargin: ConstraintDescriptionExtendable { get } + public var leadingMargin: ConstraintDescriptionExtendable { + return ConstraintDescriptionExtendable(self.backing.leadingMargin) + } @available(iOS 8.0, *) - var trailingMargin: ConstraintDescriptionExtendable { get } + public var trailingMargin: ConstraintDescriptionExtendable { + return ConstraintDescriptionExtendable(self.backing.trailingMargin) + } @available(iOS 8.0, *) - var centerXWithinMargins: ConstraintDescriptionExtendable { get } + public var centerXWithinMargins: ConstraintDescriptionExtendable { + return ConstraintDescriptionExtendable(self.backing.centerXWithinMargins) + } @available(iOS 8.0, *) - var centerYWithinMargins: ConstraintDescriptionExtendable { get } + public var centerYWithinMargins: ConstraintDescriptionExtendable { + return ConstraintDescriptionExtendable(self.backing.centerYWithinMargins) + } } /** Used to internally manage building constraint */ -internal class ConstraintDescription: ConstraintDescriptionExtendable, ConstraintDescriptionEditable, ConstraintDescriptionFinalizable { +internal class ConstraintDescription { - internal var left: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.Left) } - internal var top: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.Top) } - internal var right: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.Right) } - internal var bottom: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.Bottom) } - internal var leading: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.Leading) } - internal var trailing: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.Trailing) } - internal var width: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.Width) } - internal var height: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.Height) } - internal var centerX: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.CenterX) } - internal var centerY: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.CenterY) } - internal var baseline: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.Baseline) } + private var left: ConstraintDescription { return self.addConstraint(ConstraintAttributes.Left) } + private var top: ConstraintDescription { return self.addConstraint(ConstraintAttributes.Top) } + private var right: ConstraintDescription { return self.addConstraint(ConstraintAttributes.Right) } + private var bottom: ConstraintDescription { return self.addConstraint(ConstraintAttributes.Bottom) } + private var leading: ConstraintDescription { return self.addConstraint(ConstraintAttributes.Leading) } + private var trailing: ConstraintDescription { return self.addConstraint(ConstraintAttributes.Trailing) } + private var width: ConstraintDescription { return self.addConstraint(ConstraintAttributes.Width) } + private var height: ConstraintDescription { return self.addConstraint(ConstraintAttributes.Height) } + private var centerX: ConstraintDescription { return self.addConstraint(ConstraintAttributes.CenterX) } + private var centerY: ConstraintDescription { return self.addConstraint(ConstraintAttributes.CenterY) } + private var baseline: ConstraintDescription { return self.addConstraint(ConstraintAttributes.Baseline) } @available(iOS 8.0, *) - internal var firstBaseline: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.FirstBaseline) } + private var firstBaseline: ConstraintDescription { return self.addConstraint(ConstraintAttributes.FirstBaseline) } @available(iOS 8.0, *) - internal var leftMargin: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.LeftMargin) } + private var leftMargin: ConstraintDescription { return self.addConstraint(ConstraintAttributes.LeftMargin) } @available(iOS 8.0, *) - internal var rightMargin: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.RightMargin) } + private var rightMargin: ConstraintDescription { return self.addConstraint(ConstraintAttributes.RightMargin) } @available(iOS 8.0, *) - internal var topMargin: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.TopMargin) } + private var topMargin: ConstraintDescription { return self.addConstraint(ConstraintAttributes.TopMargin) } @available(iOS 8.0, *) - internal var bottomMargin: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.BottomMargin) } + private var bottomMargin: ConstraintDescription { return self.addConstraint(ConstraintAttributes.BottomMargin) } @available(iOS 8.0, *) - internal var leadingMargin: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.LeadingMargin) } + private var leadingMargin: ConstraintDescription { return self.addConstraint(ConstraintAttributes.LeadingMargin) } @available(iOS 8.0, *) - internal var trailingMargin: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.TrailingMargin) } + private var trailingMargin: ConstraintDescription { return self.addConstraint(ConstraintAttributes.TrailingMargin) } @available(iOS 8.0, *) - internal var centerXWithinMargins: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.CenterXWithinMargins) } + private var centerXWithinMargins: ConstraintDescription { return self.addConstraint(ConstraintAttributes.CenterXWithinMargins) } @available(iOS 8.0, *) - internal var centerYWithinMargins: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.CenterYWithinMargins) } + private var centerYWithinMargins: ConstraintDescription { return self.addConstraint(ConstraintAttributes.CenterYWithinMargins) } // MARK: initializer @@ -246,108 +339,69 @@ internal class ConstraintDescription: ConstraintDescriptionExtendable, Constrain self.toItem = ConstraintItem(object: nil, attributes: ConstraintAttributes.None) } - // MARK: equalTo - - internal func equalTo(other: ConstraintItem) -> ConstraintDescriptionEditable { - return self.constrainTo(other, relation: .Equal) - } - internal func equalTo(other: RelationTarget) -> ConstraintDescriptionEditable { - return self.constrainTo(other, relation: .Equal) - } - @available(iOS 7.0, *) - internal func equalTo(other: LayoutSupport) -> ConstraintDescriptionEditable { - return self.constrainTo(other, relation: .Equal) - } - - // MARK: lessThanOrEqualTo - - internal func lessThanOrEqualTo(other: ConstraintItem) -> ConstraintDescriptionEditable { - return self.constrainTo(other, relation: .LessThanOrEqualTo) - } - internal func lessThanOrEqualTo(other: RelationTarget) -> ConstraintDescriptionEditable { - return self.constrainTo(other, relation: .LessThanOrEqualTo) - } - @available(iOS 7.0, *) - internal func lessThanOrEqualTo(other: LayoutSupport) -> ConstraintDescriptionEditable { - return self.constrainTo(other, relation: .LessThanOrEqualTo) - } - - // MARK: greaterThanOrEqualTo - - internal func greaterThanOrEqualTo(other: ConstraintItem) -> ConstraintDescriptionEditable { - return self.constrainTo(other, relation: .GreaterThanOrEqualTo) - } - internal func greaterThanOrEqualTo(other: RelationTarget) -> ConstraintDescriptionEditable { - return self.constrainTo(other, relation: .GreaterThanOrEqualTo) - } - @available(iOS 7.0, *) - internal func greaterThanOrEqualTo(other: LayoutSupport) -> ConstraintDescriptionEditable { - return self.constrainTo(other, relation: .GreaterThanOrEqualTo) - } - // MARK: multiplier - internal func multipliedBy(amount: FloatConvertible) -> ConstraintDescriptionEditable { + private func multipliedBy(amount: FloatConvertible) -> ConstraintDescription { self.multiplier = amount.floatValue return self } - internal func dividedBy(amount: FloatConvertible) -> ConstraintDescriptionEditable { + private func dividedBy(amount: FloatConvertible) -> ConstraintDescription { self.multiplier = 1.0 / amount.floatValue; return self } // MARK: offset - internal func offset(amount: FloatConvertible) -> ConstraintDescriptionEditable { + private func offset(amount: FloatConvertible) -> ConstraintDescription { self.constant = amount.floatValue return self } - internal func offset(amount: CGPoint) -> ConstraintDescriptionEditable { + private func offset(amount: CGPoint) -> ConstraintDescription { self.constant = amount return self } - internal func offset(amount: CGSize) -> ConstraintDescriptionEditable { + private func offset(amount: CGSize) -> ConstraintDescription { self.constant = amount return self } - internal func offset(amount: EdgeInsets) -> ConstraintDescriptionEditable { + private func offset(amount: EdgeInsets) -> ConstraintDescription { self.constant = amount return self } // MARK: inset - internal func inset(amount: FloatConvertible) -> ConstraintDescriptionEditable { + private func inset(amount: FloatConvertible) -> ConstraintDescription { let value = CGFloat(amount.floatValue) self.constant = EdgeInsets(top: value, left: value, bottom: -value, right: -value) return self } - internal func inset(amount: EdgeInsets) -> ConstraintDescriptionEditable { + private func inset(amount: EdgeInsets) -> ConstraintDescription { self.constant = EdgeInsets(top: amount.top, left: amount.left, bottom: -amount.bottom, right: -amount.right) return self } // MARK: priority - internal func priority(priority: FloatConvertible) -> ConstraintDescriptionFinalizable { + private func priority(priority: FloatConvertible) -> ConstraintDescription { self.priority = priority.floatValue return self } - internal func priorityRequired() -> ConstraintDescriptionFinalizable { + private func priorityRequired() -> ConstraintDescription { return self.priority(1000.0) } - internal func priorityHigh() -> ConstraintDescriptionFinalizable { + private func priorityHigh() -> ConstraintDescription { return self.priority(750.0) } - internal func priorityMedium() -> ConstraintDescriptionFinalizable { + private func priorityMedium() -> ConstraintDescription { #if os(iOS) || os(tvOS) return self.priority(500.0) #else return self.priority(501.0) #endif } - internal func priorityLow() -> ConstraintDescriptionFinalizable { + private func priorityLow() -> ConstraintDescription { return self.priority(250.0) } @@ -416,35 +470,32 @@ internal class ConstraintDescription: ConstraintDescriptionExtendable, Constrain return self } - private func constrainTo(other: ConstraintItem, relation: ConstraintRelation) -> ConstraintDescription { - if other.attributes != ConstraintAttributes.None { - let toLayoutAttributes = other.attributes.layoutAttributes + private func constrainTo(other: RelationTarget, relation: ConstraintRelation) -> ConstraintDescription { + if let constant = other as? FloatConvertible { + self.constant = constant.floatValue + } + + let item = other.constraintItem + + if item.attributes != ConstraintAttributes.None { + let toLayoutAttributes = item.attributes.layoutAttributes if toLayoutAttributes.count > 1 { let fromLayoutAttributes = self.fromItem.attributes.layoutAttributes if toLayoutAttributes != fromLayoutAttributes { NSException(name: "Invalid Constraint", reason: "Cannot constrain to multiple non identical attributes", userInfo: nil).raise() return self } - other.attributes = ConstraintAttributes.None + item.attributes = ConstraintAttributes.None } } - self.toItem = other + self.toItem = item self.relation = relation return self } - private func constrainTo(other: RelationTarget, relation: ConstraintRelation) -> ConstraintDescription { - return constrainTo(other.constraintItem, relation: relation) - } - @available(iOS 7.0, *) private func constrainTo(other: LayoutSupport, relation: ConstraintRelation) -> ConstraintDescription { - return constrainTo(ConstraintItem(object: self, attributes: ConstraintAttributes.None), relation: relation) - } - - private func constrainTo(other: FloatConvertible, relation: ConstraintRelation) -> ConstraintDescription { - self.constant = other.floatValue - return constrainTo(ConstraintItem(object: nil, attributes: ConstraintAttributes.None), relation: relation) + return constrainTo(ConstraintItem(object: other, attributes: ConstraintAttributes.None), relation: relation, location: location) } } diff --git a/Source/ConstraintMaker.swift b/Source/ConstraintMaker.swift index 154b9dd..be38201 100644 --- a/Source/ConstraintMaker.swift +++ b/Source/ConstraintMaker.swift @@ -129,11 +129,11 @@ public class ConstraintMaker { internal let view: View internal var constraintDescriptions = [ConstraintDescription]() - internal func makeConstraintDescription(attributes: ConstraintAttributes) -> ConstraintDescription { + internal func makeConstraintDescription(attributes: ConstraintAttributes) -> ConstraintDescriptionExtendable { let item = ConstraintItem(object: self.view, attributes: attributes) let constraintDescription = ConstraintDescription(fromItem: item) self.constraintDescriptions.append(constraintDescription) - return constraintDescription + return ConstraintDescriptionExtendable(constraintDescription) } internal class func prepareConstraints(view view: View, file: String = "Unknown", line: UInt = 0, @noescape closure: (make: ConstraintMaker) -> Void) -> [Constraint] {