Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to do conditional assignment to constants in Swift?

I would like to create an immutable value that is assigned different values depending on a condition. In Scala I would be able to write the following:

    let attribs = if #available(iOS 8.2, *) {
        [ NSFontAttributeName: UIFont.systemFontOfSize(30, weight: UIFontWeightLight) ]
    } else {
        [ NSFontAttributeName: UIFont.systemFontOfSize(30) ]
    }

but since Swift if statements don't return the result of the executed code block that doesn't work.

If the test was for a normal Bool I could use the ternary conditional operator

    let attribs = #available(iOS 8.2, *) ?
        [ NSFontAttributeName: UIFont.systemFontOfSize(30, weight: UIFontWeightLight) ]
    :
        [ NSFontAttributeName: UIFont.systemFontOfSize(30) ]

but that doesn't work for the iOS version tests, I get the following error:

#available may only be used as condition of an 'if', 'guard' or 'while' statement.

I feel like I'm stuck with a var, but unless I also make it optional I end up with a double assignment in most cases, which seems so ugly and unnecessary?

    var attribs = [ NSFontAttributeName: UIFont.systemFontOfSize(30) ]
    if #available(iOS 8.2, *) {
        [ NSFontAttributeName: UIFont.systemFontOfSize(30, weight: UIFontWeightLight) ]
    }

Thanks for any help!

like image 781
srcmonster Avatar asked Dec 03 '16 16:12

srcmonster


3 Answers

You could also do this

var someConstant: String {
    if #available(iOS 9, *) {
        return "iOS 9"
    } else {
        return "not iOS 9"
    }
}

By doing this you can't assign a value to the variable someConstant even if it is a var and not a let because it is a calculated property

Another way of doing this would be to use free functions.

let someConstant: String = {
    if #available(iOS 9, *) {
        return "iOS 9"
    } else {
        return "not iOS 9"
    }
}()

The difference between the first example from the second example is that the second example is only instantiated once.

like image 116
Zonily Jame Avatar answered Oct 23 '22 09:10

Zonily Jame


I think you want something like this:

let value: String
if #available(iOS 9, *) {
    value = "iOS 9 is available"
} else {
    value = "iOS 9 and up only"
}
print(value) // iOS 9 is available
like image 44
bsarrazin Avatar answered Oct 23 '22 09:10

bsarrazin


Do the declaration and assignment on two separate lines:

let attribs: [NSAttributedString.Key: Any]
if #available(iOS 8.2, *) {
    attribs = [.font: UIFont.systemFont(ofSize: 30, weight: .light)]
} else {
    attribs = [.font: UIFont.systemFont(ofSize: 30)]
}

Even though it is a let, you can do the assignment (only once per path of execution) on a separate line.

like image 10
Rob Avatar answered Oct 23 '22 10:10

Rob