Ben Ben - 2 months ago 7
Swift Question

Converting a JSON into a Model Value in Swift

In my quest to learn more about Swift, I'm looking at ways to improve my app and noticed a few places where I'm making assumptions where perhaps I shouldn't be.

When creating a new object, lets say a 'student', they need things like a name (

String
), age (
Int
) and score (
Float
). I read these from a
JSON
file, and put them into an object like this:

// note, details is a [String:Any] type
let name = details["name"] as! String
let age = details["age"] as! Int
let score = Float(details["score"])
self.student = Student(name: name, tutor_group: tutor_group, score: score)


So my questions are as follows;
1. How should I modify my code to check that if a value is not a number, where it should be, the variable becomes just
nil
, or even better 0?
2. What if the key in the dictionary doesn't exist?
3. Are the different ways to do this, and if so, which is best practice?

Note that I want to keep this code as short as possible -
if
/
else
statements for each line are not what I'm looking for.

Thank you so much in advance!

Answer

The Official Solution

Recently Apple described the suggested way to face this problem.

You can define the Student struct (or class) this way

struct Student {

    let name: String
    let age: Int
    let score: Float

    init?(json: [String:Any]) {
        guard
            let name = json["name"] as? String,
            let age = json["age"] as? Int,
            let score = json["score"] as? Float
            else { return nil }
        self.name = name
        self.age = age
        self.score = score
    }
}

Benefits of this approach

  1. You encapsulate the logic to convert a JSON into a Student inside the Student struct itself
  2. If the JSON doesn't contain a valid data (e.g. there is no age field with a valid Int) then the initializer fails and returns nil. This means you cannot create a Student with missing fields and this is a good thing and this scenario will not cause a crash.

More

The post I linked before also describe a more advanced approach where a missing fields throws an exception. However if you don't need to log (or notify to the caller) why the initialization failed you don't need this.