Apple文档显示了“创建词典”下的一个令人不安的空白区域。 UIKit参考文献here的一部分。
有没有人找到NSDictionaryOfVariableBindings
宏的替代品,或者我们是否只想写自己的宏?
编辑 - 根据this,也许正确的方法是编写一个全局函数来处理这个问题?看起来复杂的宏完全没有了。
答案 0 :(得分:59)
根据Apple源代码:
NSDictionaryOfVariableBindings(v1,v2,v3)相当于[NSDictionary dictionaryWithObjectsAndKeys:v1,@" v1",v2,@" v2",v3,@" v3& #34;,nil];
所以在Swift中你可以使用:
let bindings = ["v1": v1, "v2": v2, "v3": v3]
答案 1 :(得分:28)
NSDictionaryOfVariableBindings
是一个宏。 Swift中没有宏。这么多。
尽管如此,您可以轻松编写Swift函数,为字符串中的视图指定字符串名称,然后将该字典传递到constraintsWithVisualFormat
。不同之处在于,与Objective-C不同,Swift无法为这些视图看到您的名称;你必须让组成一些新的名称。
[要明确的是,您的Objective-C 代码不能看到您的变量名称;就是说,在宏观评估时,预处理器在源代码上作为文本进行操作并重写它 - 所以它可以只在引号内使用变量名的文本(制作字符串)和在外面(制造价值)来形成字典。但是使用Swift,没有预处理器。]
所以,这就是我的工作:
func dictionaryOfNames(arr:UIView...) -> Dictionary<String,UIView> {
var d = Dictionary<String,UIView>()
for (ix,v) in arr.enumerate(){
d["v\(ix+1)"] = v
}
return d
}
你打电话给它并像这样使用它:
let d = dictionaryOfNames(myView, myOtherView, myFantasicView)
myView.addConstraints(
NSLayoutConstraint.constraintsWithVisualFormat(
"H:|[v2]|", options: nil, metrics: nil, views: d)
)
问题在于由您决定您的可视格式字符串中myOtherView
的名称将为v2
(因为它在列表中排名第二)传入dictionaryOfNames()
)。但我可以忍受这一点,只是为了避免每次手工输入字典的乏味。
当然,您也可以在Objective-C中或多或少地编写相同的功能。只是因为宏已经存在而你没有打扰!
答案 2 :(得分:2)
该功能基于宏扩展,目前Swift不支持。
我认为目前在Swift中没有办法做类似的事情。我相信你不能写自己的替代品。
我担心你必须手动展开字典定义,即使这意味着重复每个名字两次。
答案 3 :(得分:1)
ObjC运行时救援!
我创建了一个替代解决方案,但只有在每个视图都是同一个对象的实例变量时它才有效。
func DictionaryOfInstanceVariables(container:AnyObject, objects: String ...) -> [String:AnyObject] {
var views = [String:AnyObject]()
for objectName in objects {
guard let object = object_getIvar(container, class_getInstanceVariable(container.dynamicType, objectName)) else {
assertionFailure("\(objectName) is not an ivar of: \(container)");
continue
}
views[objectName] = object
}
return views
}
可以像这样使用:
class ViewController: UIViewController {
var childA: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = UIColor.redColor()
return view
}()
var childB: UIButton = {
let view = UIButton()
view.setTitle("asdf", forState: .Normal)
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = UIColor.blueColor()
return view
}()
override func viewDidLoad() {
super.viewDidLoad()
self.view.addSubview(childA)
self.view.addSubview(childB)
let views = DictionaryOfInstanceVariables(self, objects: "childA", "childB")
self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[childA]|", options: [], metrics: nil, views: views))
self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[childB]|", options: [], metrics: nil, views: views))
self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[childA][childB(==childA)]|", options: [], metrics: nil, views: views))
}
}
不幸的是,您仍然必须以字符串形式输入变量名称,但如果存在拼写错误,它至少会断言。这绝对不会在所有情况下都能奏效,但仍然有用
答案 4 :(得分:0)
将所有视图存储为属性后,您还可以使用如下反射:
extension ViewController {
func views() -> Dictionary<String, AnyObject> {
var views = dictionaryOfProperties()
views.forEach {
if !($1 is UIView) {
views[$0] = nil
}
}
return views
}
}
extension NSObject {
func dictionaryOfProperties() -> Dictionary<String, AnyObject> {
var result = Dictionary<String, AnyObject>()
let mirror = Mirror(reflecting: self)
for case let(label?, value) in mirror.children {
result[label] = value as? AnyObject
}
return result
}
}
答案 5 :(得分:0)
所以我一起砍了一些似乎可行的东西:
func dictionaryOfVariableBindings(container: Any, views:UIView...) -> Dictionary<String, UIView> {
var d = Dictionary<String, UIView>()
let mirror = Mirror(reflecting: container)
let _ = mirror.children.compactMap {
guard let name = $0.label, let view = $0.value as? UIView else { return }
guard views.contains(view) else { return }
d[name] = view
}
return d
}
用法:
let views = dictionaryOfVariableBindings(container: self, views: imageView)
答案 6 :(得分:0)
基于cherpak-evgeny的https://stackoverflow.com/a/55086673/1058199,此UIViewController扩展假定容器为self
,即当前的viewController实例。
extension UIViewController {
// Alex Zavatone 06/04/2019
// Using reflection, get the string name of the UIView properties passed in
// to create a dictionary of ["viewPropertyName": viewPropertyObject…] like
// Objective-C's NSDictionaryForVariableBindings.
func dictionaryOfBindings(_ arrayOfViews:[UIView?]) -> Dictionary<String, UIView> {
var bindings = Dictionary<String, UIView>()
let viewMirror = Mirror(reflecting: self)
let _ = viewMirror.children.compactMap {
guard let name = $0.label, let view = $0.value as? UIView else { return }
guard arrayOfViews.contains(view) else { return }
bindings[name] = view
}
return bindings
}
}
在您的viewController中像这样使用它:
let viewArray = [mySwitch, myField, mySpinner, aStepper, someView]
let constraintsDictionary = dictionaryOfBindings(viewArray)
在Xcode 10.2.1和Swift 4.2中进行了测试。
非常感谢Cherpak Evgeny首先编写它。