Luke Sapan Luke Sapan - 5 months ago 18
Swift Question

Guard when setting multiple class properties in Swift 2

It's trivial enough to do something like this:

class Collection {
init(json: [String: AnyObject]){
guard let id = json["id"] as? Int, name = json["name"] as? String else {
print("Oh noes, bad JSON!")
return
}
}
}


In that case we were using
let
to initialize local variables. However, modifying it to use class properties causes it to fail:

class Collection {

let id: Int
let name: String

init(json: [String: AnyObject]){
guard id = json["id"] as? Int, name = json["name"] as? String else {
print("Oh noes, bad JSON!")
return
}
}

}


It complains that
let
or
var
needs to be used but obviously that isn't the case. What's the proper way to do this in Swift 2?

Answer

In the if let, you are unwrapping values from the optional as new local variables. You can’t unwrap into existing variables. Instead, you have to unwrap, then assign i.e.

class Collection {

    let id: Int
    let name: String

    init?(json: [String: AnyObject]){
        // alternate type pattern matching syntax you might like to try
        guard case let (id as Int, name as String) = (json["id"],json["name"]) 
        else {
            print("Oh noes, bad JSON!")
            self.id = 0     // must assign to all values
            self.name = ""  // before returning nil
            return nil
        }
        // now, assign those unwrapped values to self
        self.id = id
        self.name = name
    }

}

This is not specific to class properties - you can’t conditionally bind into any variable, for example this doesn’t work:

var i = 0
let s = "1"
if i = Int(s) {  // nope

}

Instead you need to do:

if let j = Int(s) {
  i = j
}

(though of course, in this case you’d be better with let i = Int(s) ?? 0)