Ios NSDictionaryOfVariableBindings swift等价物?

Ios NSDictionaryOfVariableBindings swift等价物?,ios,swift,Ios,Swift,苹果的文档在UIKit参考的“创建字典”部分显示了一个令人不安的空白 是否有人找到了NSDictionaryOfVariableBindings宏的替代品,或者我们只需要编写自己的 编辑-根据可能正确的方法是编写一个全局函数来处理这个问题?看起来复杂的宏已经完全过时了。该功能是基于当前Swift不支持的宏扩展的 我认为目前没有任何方法可以在Swift中做类似的事情。我相信你不能自己写替代品 恐怕您必须手动展开词典定义,即使这意味着每个名称重复两次。根据苹果的源代码: NSDictionaryOf

苹果的文档在UIKit参考的“创建字典”部分显示了一个令人不安的空白

是否有人找到了
NSDictionaryOfVariableBindings
宏的替代品,或者我们只需要编写自己的


编辑-根据可能正确的方法是编写一个全局函数来处理这个问题?看起来复杂的宏已经完全过时了。

该功能是基于当前Swift不支持的宏扩展的

我认为目前没有任何方法可以在Swift中做类似的事情。我相信你不能自己写替代品


恐怕您必须手动展开词典定义,即使这意味着每个名称重复两次。

根据苹果的源代码:

NSDictionaryOfVariableBindings(v1、v2、v3)等价于[NSDictionaryWithObjectsSandKeys:v1、@“v1”、v2、@“v2”、v3、@“v3”、nil]

因此,在Swift中,您可以使用以下方法执行相同操作:

let bindings = ["v1": v1, "v2": v2, "v3": v3]

NSDictionaryOfVariableBindings
正如您所说,是一个宏。Swift中没有宏。到此为止

尽管如此,您仍然可以轻松编写Swift函数,为字典中的视图指定字符串名称,然后将该字典传递到
constraintsWithVisualFormat
。区别在于,与Objective-C不同,斯威夫特看不到这些视图的名称;你将不得不让它组成一些新的名字

[需要明确的是,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
}
关键在于,您需要意识到,可视化格式字符串中的
myOtherView
的名称将是
v2
(因为它是传递到
dictionaryOfNames()的列表中的第二个名称)。但我可以接受这一点,只是为了避免每次手工输入字典的繁琐


当然,您也可以在Objective-C中或多或少地编写相同的函数。只是因为宏已经存在,所以您不必费心了

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
}
可以这样使用:

    let d = dictionaryOfNames(myView, myOtherView, myFantasicView)
    myView.addConstraints(
        NSLayoutConstraint.constraintsWithVisualFormat(
            "H:|[v2]|", options: nil, metrics: nil, views: d)
    )
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))

    }

}

不幸的是,您仍然必须以字符串形式键入变量名,但如果输入错误,它至少会断言。这肯定不会在所有情况下都起作用,但是很有帮助

一旦您将所有视图存储为属性,您还可以使用反射,如下所示:

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
    }
}
扩展视图控制器{
func view()->字典{
var views=dictionaryOfProperties()
视图。forEach{
如果!(1美元是UIView){
视图[$0]=零
}
}
返回视图
}
}
扩展NSObject{
func dictionaryOfProperties()->字典{
var result=Dictionary()
让镜子=镜子(反射:自身)
对于mirror.children中的case let(标签?,值){
结果[标签]=值为?任何对象
}
返回结果
}
}

所以我把一些似乎有效的东西拼凑在一起:

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
}
基于cherpak evgeny的分析,此UIViewController扩展假定容器是当前viewController实例
self

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
    }
}
在Xcode 10.2.1和Swift 4.2中测试


首先非常感谢您的帮助。

没错,但这也是用Objective-C编写词典的一种方法。有趣的是,他们只是删除了宏本身…但在Swift中留下了定义宏的注释(如果打开Swift的NSLAYOUTSCONSTRAINT,请检查代码)。我真的不喜欢写两次我的变量名,特别是因为你可能会在键中拼写错误并导致崩溃。这是一个小麻烦,但也是一个麻烦。根据XCode 6 beta 2发行说明,字典还没有连接到NSDictionary。在此之前,您可能希望使用这些值显式创建NSDictionary或NSMutable字典。使用本机Swift字典作为参数来约束VisualFormat:options:metrics:views:当前会导致崩溃。@JohnM.P.Knox字典与NSDictionary之间不存在桥接问题。它是桥;当然是桥了!传递一本本地的Swift字典在这里非常有效。这不是问题所在。问题是没有宏,也不能“内省”变量名,因此不可能有与
NSDictionaryOfVariableBindings
@Stakenborg等效的名称。它们没有“删除宏,但留下了注释”。没有快速标题!您正在查看Objective-C标题(通过自发的实时生成的Swift翻译)。宏没有翻译,因为Swift中没有宏。对于
选项:
参数(XCode 7 Swift 2.0)
,请使用
NSLayoutFormatOptions(rawValue:0)
而不是
nil
。Maverick呃,没有。没有人会说
NSLayoutFormatOptions(rawValue:0)
。您只需在Swift 2.Yikes中说
options:[]
。我肯定会担心这个错误。也就是说,将一个视图放到字典末尾以外的地方,从而打破各种限制。但是,正如您所说,由开发人员来理解命名约定。@stuckj幸运的是,现在我们已经有了锚符号和堆栈视图,使用可视化格式的原因现在已经很少了。:)对于您的解决方案,值得注意的是:这些视图必须存储为object-c对象的iVar。您是上帝。我已经在Xcode 10.2.1下测试过了,它可以正常工作。我将发布一个modi
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
    }
}
let viewArray = [mySwitch, myField, mySpinner, aStepper, someView]
let constraintsDictionary = dictionaryOfBindings(viewArray)