Guard when setting multiple class properties in Sw

2020-07-13 02:53发布

问题:

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?

回答1:

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)