Solution for Ch 25 Challenge: Add Constraints Programmatically

Using the NSLayoutConstraint class init API

Update to Document.swift

@IBOutlet weak var scrollView: NSScrollView!
@IBOutlet weak var addButton: NSButton!
@IBOutlet weak var removeButton: NSButton!

override func windowControllerDidLoadNib(_ windowController: NSWindowController) {
  let superview = addButton.superview!
  
  addButton.translatesAutoresizingMaskIntoConstraints = false
  superview.addConstraint(NSLayoutConstraint(item: addButton, attribute: .top, relatedBy: .equal, toItem: superview, attribute: .top, multiplier: 1.0, constant: 20.0))
  superview.addConstraint(NSLayoutConstraint(item: addButton, attribute: .trailing, relatedBy: .equal, toItem: superview, attribute: .trailing, multiplier: 1.0, constant: -20.0))
  
  removeButton.translatesAutoresizingMaskIntoConstraints = false
  superview.addConstraint(NSLayoutConstraint(item: removeButton, attribute: .trailing, relatedBy: .equal, toItem: addButton, attribute: .trailing, multiplier: 1.0, constant: 0.0))
  superview.addConstraint(NSLayoutConstraint(item: removeButton, attribute: .top, relatedBy: .equal, toItem: addButton, attribute: .bottom, multiplier: 1.0, constant: 12.0))
  superview.addConstraint(NSLayoutConstraint(item: removeButton, attribute: .width, relatedBy: .equal, toItem: addButton, attribute: .width, multiplier: 1.0, constant: 0.0))
  superview.addConstraint(NSLayoutConstraint(item: removeButton, attribute: .bottom, relatedBy: .lessThanOrEqual, toItem: superview, attribute: .bottom, multiplier: 1.0, constant: -20.0))
  
  scrollView.translatesAutoresizingMaskIntoConstraints = false
  superview.addConstraint(NSLayoutConstraint(item: scrollView, attribute: .top, relatedBy: .equal, toItem: superview, attribute: .top, multiplier: 1.0, constant: 20.0))
  superview.addConstraint(NSLayoutConstraint(item: scrollView, attribute: .leading, relatedBy: .equal, toItem: superview, attribute: .leading, multiplier: 1.0, constant: 20.0))
  superview.addConstraint(NSLayoutConstraint(item: scrollView, attribute: .bottom, relatedBy: .equal, toItem: superview, attribute: .bottom, multiplier: 1.0, constant: -20.0))
  superview.addConstraint(NSLayoutConstraint(item: scrollView, attribute: .trailing, relatedBy: .equal, toItem: addButton, attribute: .leading, multiplier: 1.0, constant: -12.0))
  superview.addConstraint(NSLayoutConstraint(item: scrollView, attribute: .width, relatedBy: .greaterThanOrEqual, toItem: nil, attribute: .width, multiplier: 1.0, constant: 300.0))
}

Using the Visual Format Language

Update to Document.swift

@IBOutlet weak var scrollView: NSScrollView!
@IBOutlet weak var addButton: NSButton!
@IBOutlet weak var removeButton: NSButton!

override func windowControllerDidLoadNib(_ windowController: NSWindowController) {  
  addButton.translatesAutoresizingMaskIntoConstraints = false
  removeButton.translatesAutoresizingMaskIntoConstraints = false
  scrollView.translatesAutoresizingMaskIntoConstraints = false
  
  let d: [String : Any] = ["SV" : scrollView, "AB" : addButton, "RB" : removeButton]
  NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: "H:|-[SV(>=300)]-[AB(==RB)]-|", options: .alignAllTop, metrics: nil, views: d))
  NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: "V:|-[AB]-[RB]-(>=20)-|", options: .alignAllTrailing, metrics: nil, views: d))
  NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: "V:|-[SV]-|", options: [], metrics: nil, views: d))
}