mirror of https://github.com/SnapKit/SnapKit
Improve debugging and allow width/height constraints to be installed on from view
This commit is contained in:
parent
3d9a449e37
commit
9ef9ae6f9f
|
@ -58,6 +58,9 @@ public class Constraint {
|
||||||
public func updatePriorityMedium() -> Void { fatalError("Must be implemented by Concrete subclass.") }
|
public func updatePriorityMedium() -> Void { fatalError("Must be implemented by Concrete subclass.") }
|
||||||
public func updatePriorityLow() -> Void { fatalError("Must be implemented by Concrete subclass.") }
|
public func updatePriorityLow() -> Void { fatalError("Must be implemented by Concrete subclass.") }
|
||||||
|
|
||||||
|
internal var makerFile: String = "Unknown"
|
||||||
|
internal var makerLine: UInt = 0
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -191,23 +194,26 @@ internal class ConcreteConstraint: Constraint {
|
||||||
self.priority = priority
|
self.priority = priority
|
||||||
}
|
}
|
||||||
|
|
||||||
internal func installOnView(updateExisting: Bool = false) -> [LayoutConstraint] {
|
internal func installOnView(updateExisting: Bool = false, file: String? = nil, line: UInt? = nil) -> [LayoutConstraint] {
|
||||||
var installOnView: View? = nil
|
var installOnView: View? = nil
|
||||||
if self.toItem.view != nil {
|
if self.toItem.view != nil {
|
||||||
installOnView = closestCommonSuperviewBetween(self.fromItem.view, self.toItem.view)
|
installOnView = closestCommonSuperviewBetween(self.fromItem.view, self.toItem.view)
|
||||||
if installOnView == nil {
|
if installOnView == nil {
|
||||||
NSException(name: "Cannot Install Constraint", reason: "No common superview between views", userInfo: nil).raise()
|
NSException(name: "Cannot Install Constraint", reason: "No common superview between views (@\(self.makerFile)#\(self.makerLine))", userInfo: nil).raise()
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
installOnView = self.fromItem.view?.superview
|
|
||||||
if installOnView == nil {
|
let widthAttr = ConstraintAttributes.Width
|
||||||
if self.fromItem.attributes == ConstraintAttributes.Width || self.fromItem.attributes == ConstraintAttributes.Height {
|
let heightAttr = ConstraintAttributes.Height
|
||||||
installOnView = self.fromItem.view
|
let sizeAttrs = widthAttr | heightAttr
|
||||||
}
|
|
||||||
|
if self.fromItem.attributes == widthAttr || self.fromItem.attributes == heightAttr || self.fromItem.attributes == sizeAttrs {
|
||||||
|
installOnView = self.fromItem.view
|
||||||
|
} else {
|
||||||
|
installOnView = self.fromItem.view?.superview
|
||||||
if installOnView == nil {
|
if installOnView == nil {
|
||||||
NSException(name: "Cannot Install Constraint", reason: "Missing superview", userInfo: nil).raise()
|
NSException(name: "Cannot Install Constraint", reason: "Missing superview (@\(self.makerFile)#\(self.makerLine))", userInfo: nil).raise()
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -215,7 +221,7 @@ internal class ConcreteConstraint: Constraint {
|
||||||
|
|
||||||
if let installedOnView = self.installInfo?.view {
|
if let installedOnView = self.installInfo?.view {
|
||||||
if installedOnView != installOnView {
|
if installedOnView != installOnView {
|
||||||
NSException(name: "Cannot Install Constraint", reason: "Already installed on different view.", userInfo: nil).raise()
|
NSException(name: "Cannot Install Constraint", reason: "Already installed on different view. (@\(self.makerFile)#\(self.makerLine))", userInfo: nil).raise()
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
return self.installInfo?.layoutConstraints.allObjects as? [LayoutConstraint] ?? []
|
return self.installInfo?.layoutConstraints.allObjects as? [LayoutConstraint] ?? []
|
||||||
|
|
|
@ -115,10 +115,14 @@ public class ConstraintMaker {
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
internal init(view: View) {
|
internal init(view: View, file: String, line: UInt) {
|
||||||
self.view = view
|
self.view = view
|
||||||
|
self.file = file
|
||||||
|
self.line = line
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal let file: String
|
||||||
|
internal let line: UInt
|
||||||
internal let view: View
|
internal let view: View
|
||||||
internal var constraintDescriptions = [ConstraintDescription]()
|
internal var constraintDescriptions = [ConstraintDescription]()
|
||||||
|
|
||||||
|
@ -129,60 +133,71 @@ public class ConstraintMaker {
|
||||||
return constraintDescription
|
return constraintDescription
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class func prepareConstraints(view: View, @noescape closure: (make: ConstraintMaker) -> Void) -> [Constraint] {
|
internal class func prepareConstraints(#view: View, file: String = "Unknown", line: UInt = 0, @noescape closure: (make: ConstraintMaker) -> Void) -> [Constraint] {
|
||||||
let maker = ConstraintMaker(view: view)
|
let maker = ConstraintMaker(view: view, file: file, line: line)
|
||||||
closure(make: maker)
|
closure(make: maker)
|
||||||
|
|
||||||
return maker.constraintDescriptions.map { $0.constraint }
|
let constraints = maker.constraintDescriptions.map { $0.constraint }
|
||||||
|
for constraint in constraints {
|
||||||
|
constraint.makerFile = maker.file
|
||||||
|
constraint.makerLine = maker.line
|
||||||
|
}
|
||||||
|
return constraints
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class func makeConstraints(view: View, @noescape closure: (make: ConstraintMaker) -> Void) {
|
internal class func makeConstraints(#view: View, file: String = "Unknown", line: UInt = 0, @noescape closure: (make: ConstraintMaker) -> Void) {
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
view.setTranslatesAutoresizingMaskIntoConstraints(false)
|
view.setTranslatesAutoresizingMaskIntoConstraints(false)
|
||||||
#else
|
#else
|
||||||
view.translatesAutoresizingMaskIntoConstraints = false
|
view.translatesAutoresizingMaskIntoConstraints = false
|
||||||
#endif
|
#endif
|
||||||
let maker = ConstraintMaker(view: view)
|
let maker = ConstraintMaker(view: view, file: file, line: line)
|
||||||
closure(make: maker)
|
closure(make: maker)
|
||||||
|
|
||||||
let constraints = maker.constraintDescriptions.map { $0.constraint as! ConcreteConstraint }
|
let constraints = maker.constraintDescriptions.map { $0.constraint as! ConcreteConstraint }
|
||||||
for constraint in constraints {
|
for constraint in constraints {
|
||||||
|
constraint.makerFile = maker.file
|
||||||
|
constraint.makerLine = maker.line
|
||||||
constraint.installOnView(updateExisting: false)
|
constraint.installOnView(updateExisting: false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class func remakeConstraints(view: View, @noescape closure: (make: ConstraintMaker) -> Void) {
|
internal class func remakeConstraints(#view: View, file: String = "Unknown", line: UInt = 0, @noescape closure: (make: ConstraintMaker) -> Void) {
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
view.setTranslatesAutoresizingMaskIntoConstraints(false)
|
view.setTranslatesAutoresizingMaskIntoConstraints(false)
|
||||||
#else
|
#else
|
||||||
view.translatesAutoresizingMaskIntoConstraints = false
|
view.translatesAutoresizingMaskIntoConstraints = false
|
||||||
#endif
|
#endif
|
||||||
let maker = ConstraintMaker(view: view)
|
let maker = ConstraintMaker(view: view, file: file, line: line)
|
||||||
closure(make: maker)
|
closure(make: maker)
|
||||||
|
|
||||||
self.removeConstraints(view)
|
self.removeConstraints(view: view)
|
||||||
let constraints = maker.constraintDescriptions.map { $0.constraint as! ConcreteConstraint }
|
let constraints = maker.constraintDescriptions.map { $0.constraint as! ConcreteConstraint }
|
||||||
for constraint in constraints {
|
for constraint in constraints {
|
||||||
|
constraint.makerFile = maker.file
|
||||||
|
constraint.makerLine = maker.line
|
||||||
constraint.installOnView(updateExisting: false)
|
constraint.installOnView(updateExisting: false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class func updateConstraints(view: View, @noescape closure: (make: ConstraintMaker) -> Void) {
|
internal class func updateConstraints(#view: View, file: String = "Unknown", line: UInt = 0, @noescape closure: (make: ConstraintMaker) -> Void) {
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
view.setTranslatesAutoresizingMaskIntoConstraints(false)
|
view.setTranslatesAutoresizingMaskIntoConstraints(false)
|
||||||
#else
|
#else
|
||||||
view.translatesAutoresizingMaskIntoConstraints = false
|
view.translatesAutoresizingMaskIntoConstraints = false
|
||||||
#endif
|
#endif
|
||||||
let maker = ConstraintMaker(view: view)
|
let maker = ConstraintMaker(view: view, file: file, line: line)
|
||||||
closure(make: maker)
|
closure(make: maker)
|
||||||
|
|
||||||
let constraints = maker.constraintDescriptions.map { $0.constraint as! ConcreteConstraint}
|
let constraints = maker.constraintDescriptions.map { $0.constraint as! ConcreteConstraint}
|
||||||
for constraint in constraints {
|
for constraint in constraints {
|
||||||
|
constraint.makerFile = maker.file
|
||||||
|
constraint.makerLine = maker.line
|
||||||
constraint.installOnView(updateExisting: true)
|
constraint.installOnView(updateExisting: true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class func removeConstraints(view: View) {
|
internal class func removeConstraints(#view: View) {
|
||||||
for existingLayoutConstraint in view.snp_installedLayoutConstraints {
|
for existingLayoutConstraint in view.snp_installedLayoutConstraints {
|
||||||
existingLayoutConstraint.snp_constraint?.uninstall()
|
existingLayoutConstraint.snp_constraint?.uninstall()
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,18 +100,38 @@ public extension LayoutConstraint {
|
||||||
return description
|
return description
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal var snp_makerFile: String? {
|
||||||
|
return self.snp_constraint?.makerFile
|
||||||
|
}
|
||||||
|
|
||||||
|
internal var snp_makerLine: UInt? {
|
||||||
|
return self.snp_constraint?.makerLine
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private var labelKey = ""
|
private var labelKey = ""
|
||||||
|
|
||||||
private func descriptionForObject(object: AnyObject) -> String {
|
private func descriptionForObject(object: AnyObject) -> String {
|
||||||
let pointerDescription = NSString(format: "%p", [object])
|
let pointerDescription = NSString(format: "%p", ObjectIdentifier(object).uintValue)
|
||||||
|
var desc = ""
|
||||||
|
|
||||||
|
desc += object.dynamicType.description()
|
||||||
|
|
||||||
if let object = object as? View {
|
if let object = object as? View {
|
||||||
return "<\(object.dynamicType.description()):\(object.snp_label ?? pointerDescription)>"
|
desc += ":\(object.snp_label ?? pointerDescription)"
|
||||||
} else if let object = object as? LayoutConstraint {
|
} else if let object = object as? LayoutConstraint {
|
||||||
return "<\(object.dynamicType.description()):\(object.snp_label ?? pointerDescription)>"
|
desc += ":\(object.snp_label ?? pointerDescription)"
|
||||||
|
} else {
|
||||||
|
desc += ":\(pointerDescription)"
|
||||||
}
|
}
|
||||||
return "<\(object.dynamicType.description()):\(pointerDescription)>"
|
|
||||||
|
if let object = object as? LayoutConstraint, let file = object.snp_makerFile, let line = object.snp_makerLine {
|
||||||
|
desc += "@\(file)#\(line)"
|
||||||
|
}
|
||||||
|
|
||||||
|
desc += ""
|
||||||
|
return desc
|
||||||
}
|
}
|
||||||
|
|
||||||
private extension NSLayoutRelation {
|
private extension NSLayoutRelation {
|
||||||
|
|
|
@ -124,8 +124,8 @@ public extension View {
|
||||||
|
|
||||||
:returns: the constraints made
|
:returns: the constraints made
|
||||||
*/
|
*/
|
||||||
public func snp_prepareConstraints(@noescape closure: (make: ConstraintMaker) -> Void) -> [Constraint] {
|
public func snp_prepareConstraints(file: String = __FILE__, line: UInt = __LINE__, @noescape closure: (make: ConstraintMaker) -> Void) -> [Constraint] {
|
||||||
return ConstraintMaker.prepareConstraints(self, closure: closure)
|
return ConstraintMaker.prepareConstraints(view: self, file: file, line: line, closure: closure)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -133,8 +133,8 @@ public extension View {
|
||||||
|
|
||||||
:param: closure that will be passed the `ConstraintMaker` to make the constraints with
|
:param: closure that will be passed the `ConstraintMaker` to make the constraints with
|
||||||
*/
|
*/
|
||||||
public func snp_makeConstraints(@noescape closure: (make: ConstraintMaker) -> Void) -> Void {
|
public func snp_makeConstraints(file: String = __FILE__, line: UInt = __LINE__, @noescape closure: (make: ConstraintMaker) -> Void) -> Void {
|
||||||
ConstraintMaker.makeConstraints(self, closure: closure)
|
ConstraintMaker.makeConstraints(view: self, file: file, line: line, closure: closure)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -144,8 +144,8 @@ public extension View {
|
||||||
|
|
||||||
:param: closure that will be passed the `ConstraintMaker` to update the constraints with
|
:param: closure that will be passed the `ConstraintMaker` to update the constraints with
|
||||||
*/
|
*/
|
||||||
public func snp_updateConstraints(@noescape closure: (make: ConstraintMaker) -> Void) -> Void {
|
public func snp_updateConstraints(file: String = __FILE__, line: UInt = __LINE__, @noescape closure: (make: ConstraintMaker) -> Void) -> Void {
|
||||||
ConstraintMaker.updateConstraints(self, closure: closure)
|
ConstraintMaker.updateConstraints(view: self, file: file, line: line, closure: closure)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -153,15 +153,15 @@ public extension View {
|
||||||
|
|
||||||
:param: closure that will be passed the `ConstraintMaker` to remake the constraints with
|
:param: closure that will be passed the `ConstraintMaker` to remake the constraints with
|
||||||
*/
|
*/
|
||||||
public func snp_remakeConstraints(@noescape closure: (make: ConstraintMaker) -> Void) -> Void {
|
public func snp_remakeConstraints(file: String = __FILE__, line: UInt = __LINE__, @noescape closure: (make: ConstraintMaker) -> Void) -> Void {
|
||||||
ConstraintMaker.remakeConstraints(self, closure: closure)
|
ConstraintMaker.remakeConstraints(view: self, file: file, line: line, closure: closure)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Removes all previously made constraints.
|
Removes all previously made constraints.
|
||||||
*/
|
*/
|
||||||
public func snp_removeConstraints() {
|
public func snp_removeConstraints() {
|
||||||
ConstraintMaker.removeConstraints(self)
|
ConstraintMaker.removeConstraints(view: self)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal var snp_installedLayoutConstraints: [LayoutConstraint] {
|
internal var snp_installedLayoutConstraints: [LayoutConstraint] {
|
||||||
|
|
Loading…
Reference in New Issue