Reputation: 354
I have a class init that is named User, and the class User contains some parameters. Now in the Offer class, you can see that I pass the User class as a param, but I want to have it as optional instead. Is there a way to have an optional class in your params? Thank you
struct User {
let uid: String
let username: String
init(uid: String, dictionary: [String: Any]) {
self.uid = uid
self.username = dictionary["username"] as? String ?? ""
}
}
struct Offer {
let user: User
let caption: String
let imageURL: String
let creationDate: Date
init(user: User, dictionary: [String: Any]) {
self.user = user
self.caption = dictionary["caption"] as? String ?? ""
self.imageURL = dictionary["image_url"] as? String ?? ""
let secondsFrom1970 = dictionary["creation_date"] as? Double ?? 0
self.creationDate = Date(timeIntervalSince1970: secondsFrom1970)
}
}
Upvotes: 0
Views: 457
Reputation: 63137
You code is muddling two distinct things: initialization of an object with a set of values for its members, and extracting those members from a dictionary. Just write two seperate initializers:
import Foundation
struct User {
let uid: String
let username: String
/*
// Due to the absence of an explicit initializer declaration,
// the compiler will synthesize an implicit member-wise initailizer like this:
init(uid: String, username: String) {
self.uid = uid
self.username = username
}
*/
}
extension User {
// Putting this initializer in an extension preserves he member-wise intializer
init?(fromDict dict: [String: Any]) {
guard let uid = dict["uid"] as? String,
let username = dict["username"] as? String
else { return nil }
self.init(uid: uid, username: username)
}
}
struct Offer {
let user: User
let caption: String
let imageURL: String
let creationDate: Date
/*
// Due to the absence of an explicit initializer declaration,
// the compiler will synthesize an implicit member-wise initailizer like this:
init(
user: User,
caption: String,
imageURL: String,
creationDate: Date
) {
self.user = user
self.caption = caption
self.imageURL = imageURL
self.creationDate = creationDate
}
*/
}
extension Offer {
// Putting this initializer in an extension preserves he member-wise intializer
init?(fromDict dict: [String: Any]) {
guard let user = dict["user"] as? User,
let caption = dict["caption"] as? String,
let imageURL = dict["image_url"] as? String,
let secondsFrom1970 = dict["creation_date"] as? Double
else { return nil }
self.init(
user: user,
caption: caption,
imageURL: imageURL,
creationDate: Date(timeIntervalSince1970: secondsFrom1970)
)
}
}
Some notes:
??
) to provide non-sensical default values in the case of nil
is really bad practice. It hides failures and silently introduces data integrity issues; don't do it.String
is not an appropriate type for a member called imageURL
. Use URL
.Codable
protocol to automate all of this boilerplate code.String
is a poor type for an ID
, primarily because it's really slow, in comparison to more suitable types like UUID
and Int
. This is particularly true in most databases, where textual comparison is much slower than Int/UUID comparison.Upvotes: 1
Reputation: 16416
First of all this is not class
this is struct
and they both are different.
you can easily create optional argument like below.
You also need to mark user
property as optional as well.
struct Offer {
let user: User?
let caption: String
let imageURL: String
let creationDate: Date
init(user: User? = nil, dictionary: [String: Any]) {
self.user = user
self.caption = dictionary["caption"] as? String ?? ""
self.imageURL = dictionary["image_url"] as? String ?? ""
let secondsFrom1970 = dictionary["creation_date"] as? Double ?? 0
self.creationDate = Date(timeIntervalSince1970: secondsFrom1970)
}
}
Upvotes: 0