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!
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
}
}
Student
inside the Student
struct itselfJSON
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 there is no way to create a Student
with missing fields (and this is a good thing) and this scenario will not cause a crash.The post I linked above also describes a more advanced approach where a missing field/value 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.
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?
let age = (details["age"] as? Int) ?? 0
age
will have the type Int
details["age"]
will return nil
, as? Int
will return an Int?
with value nil
and the nil coalescing operator ??
will set the value to 0
.Int
, the conditional cast as? Int
will return nil
and the value will be set to 0
.age
will have the Int
value that was stored in details["age"]
.For the other fields:
let name = (details["name"] as? String) ?? ""
// If score is stored as a String
let score = Float(details["score"] as? String ?? "") ?? 0
OR
// If score is stored as a number
let score = (details["score"] as? Float) ?? 0
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With