Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSDictionaryOfVariableBindings swift equivalent?

Tags:

ios

swift

The Apple documentation shows an unsettling blank space under the 'Creating a Dictionary' section of the UIKit reference here.

Has anyone found a replacement for the NSDictionaryOfVariableBindings macro, or are we expected to just write our own?

EDIT - According to this perhaps the right approach is to write a global function to handle this? Looks like complex macros are out entirely.

like image 741
Stakenborg Avatar asked Jun 06 '14 15:06

Stakenborg


3 Answers

According to Apple source code:

NSDictionaryOfVariableBindings(v1, v2, v3) is equivalent to [NSDictionary dictionaryWithObjectsAndKeys:v1, @"v1", v2, @"v2", v3, @"v3", nil];

So in Swift you can do the same using:

let bindings = ["v1": v1, "v2": v2, "v3": v3]
like image 144
jhibberd Avatar answered Oct 14 '22 01:10

jhibberd


NSDictionaryOfVariableBindings is, as you say, a macro. There are no macros in Swift. So much for that.

Nonetheless, you can easily write a Swift function to assign string names to your views in a dictionary, and then pass that dictionary into constraintsWithVisualFormat. The difference is that, unlike Objective-C, Swift can't see your names for those views; you will have to let it make up some new names.

[To be clear, it isn't that your Objective-C code could see your variable names; it's that, at macro evaluation time, the preprocessor was operating on your source code as text and rewriting it — and so it could just use the text of your variable names both inside quotes (to make strings) and outside (to make values) to form a dictionary. But with Swift, there is no preprocessor.]

So, here's what I do:

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
}

And you call it and use it like this:

    let d = dictionaryOfNames(myView, myOtherView, myFantasicView)
    myView.addConstraints(
        NSLayoutConstraint.constraintsWithVisualFormat(
            "H:|[v2]|", options: nil, metrics: nil, views: d)
    )

The catch is that it is up to you to realize that the name for myOtherView in your visual format string will be v2 (because it was second in the list passed in to dictionaryOfNames()). But I can live with that just to avoid the tedium of typing out the dictionary by hand every time.

Of course, you could equally have written more or less this same function in Objective-C. It's just that you didn't bother because the macro already existed!

like image 37
matt Avatar answered Oct 14 '22 00:10

matt


That functionality is based on macro expansion which is currently not supported in Swift.

I do not think there is any way to do something similar in Swift at the moment. I believe you cannot write your own replacement.

I'm afraid you'll have to manually unroll the dictionary definition, even if it means repeating each name twice.

like image 2
Analog File Avatar answered Oct 14 '22 01:10

Analog File