Skip to content

Instantly share code, notes, and snippets.

@helje5
Last active September 13, 2019 01:32
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save helje5/dfe3cf5ac2940756da97e757fc5706ac to your computer and use it in GitHub Desktop.
Save helje5/dfe3cf5ac2940756da97e757fc5706ac to your computer and use it in GitHub Desktop.
NSDictionaryOfVariableBindings for Swift
/**
* NSDictionaryOfVariableBindings for Swift
*
* In Objective-C you could use macros to quickly get a Dictionary of views,
* keyed on their names in the sourcecode. Like so:
*
* UILabel *label = [UILabel autolayoutView];
* NSDictionary *views = NSDictionaryOfVariableBindings(label);
*
* Which you could then use in, for example, VFL:
*
* H:|-[label]-|
*
* In Swift `NSDictionaryOfVariableBindings` is not available anymore.
*
* But we can use reflection to accomplish something similar in Swift. It
* happens at runtime, so it is much slower, but yet. So how does this work?
* In custom views or VCs you usually have a bunch of instance variables for
* the subviews you use.
*
* class MyTableViewCell : UITableViewCell, ZzViewHolder { // <===
* let label = UILabel()
* let button = UIButton()
*
* override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
* super.init(style: style, reuseIdentifier: reuseIdentifier)
*
* allViews.forEach { // <===
* $0.translatesAutoresizingMaskIntoConstraints = false
* addSubview($0)
* }
*
* NSLayoutConstraint.activate(NSLayoutConstraint.constraints(
* withVisualFormat: "H:|-[label]-[button]-|",
* options: [], metrics: nil,
* views: idToViews // <===
* ))
* }
* }
*/
public protocol ZzViewHolder {
// just a mixin protocol
}
public extension ZzViewHolder {
public var allViews : [ ZzView ] {
return Mirror(reflecting: self).children.flatMap { $0.1 as? ZzView }
}
public var idToView : [ String : ZzView ] {
// Unfortunately in Swift, we cannot return a trampoline because VFL API
// expects a [:], not an arbitrary Map protocol.
var idToView = [ String : ZzView ]()
for ( key, value ) in Mirror(reflecting: self).children {
guard let key = key, let view = value as? ZzView else { continue }
idToView[key] = view
}
return idToView
}
}
#if os(macOS)
public typealias ZzView = NSView
#else
public typealias ZzView = UIView
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment