How to make LocalizedStingKey type conform to Codable protocol in Swift?
A simple Person struct. If do not remove country property, compiler not work.
struct Person: Codable {
let name: String
let age: Int
let description: LocalizedKeyString // more words in description property
}
I decided to use String type and not add computed property because properties in my custom type is a little more.
If use computed property, the following code work:
struct Person: Codable {
let name: String
let age: Int
let description: String
var localizedDescription: LocalizedStringKey {
return LocalizedStringKey(description)
}
}
Let's say I have these two structures:
struct DataOne {
let id: String
// ...
}
struct DataTwo {
let id: String
// ...
}
And there is a separate conversion function:
extension DataOne {
func convertToDataTwo() -> DataTwo {
.init(
id: self.id,
// ...
)
}
}
At some point, the var name: String? field is added to both structures:
struct DataOne {
let id: String
var name: String?
// ...
}
struct DataTwo {
let id: String
var name: String?
// ...
}
But the assembly does not swear because the field is optional.
And when converting, the name field is lost.
Is it possible to disable the autofill of the option or to call the warnings?
I tried to find such a rule in SwiftLint, but I didn't find it.
If your var's type is written T? with no default value, and Swift synthesizes a memberwise init for your type, then the synthesized init uses a default value of nil for that var.
However, if your var's type is written Optional<T> with no default value, then the synthesized init does not use a default value.
So write this instead:
struct DataOne {
let id: String
var name: Optional<String>
// ...
}
struct DataTwo {
let id: String
var name: Optional<String>
// ...
}
Or write out your init instead of letting the compiler synthesize it:
struct DataOne {
let id: String
var name: String?
init(id: String, name: String?) {
self.id = id
self.name = name
}
}
struct DataTwo {
let id: String
var name: String?
init(id: String, name: String?) {
self.id = id
self.name = name
}
}
You can use Xcode's Editor > Refactor > Generate Memberwise Initializer command to write most of the init for you, then delete the = nil default:
I want to clear my structure.
I want to reset all the values to nil.
How do i do this???
enum HealthDataType: String, Codable {
case heartRate
case bmi
}
struct HealthDataItem: Codable {
let endDate: String
let value: String
let startDate: String
let type: HealthDataType
}
I'm trying to decode a JSON using codable. I'm wondering if there's a way to customize codable to return HelloModel's typeCustomer as type TypeOfCustomerEnum instead of String?
Example:
{
"name": "Hello",
"lastName": "World",
"typeOfCustomer": "Student"
}
enum TypeOfCustomerEnum: String {
let Student = "Student"
let Paying = "Paying"
let NonPaying = "Nonpaying"
}
struct HelloModel: Codable {
let name: String
let lastName: String
let typeOfCustomer: TypeOfCustomerEnum // JSON for TypeOfCustomer is a String but TypeOfCustomer wanted
}
The type TypeOfCustomerEnum must also conform to Codable and the cases (must be cases) should be lowercased and the literal strings must match the JSON values
enum TypeOfCustomerEnum: String, Codable {
case student = "Student"
case paying = "Paying"
case nonPaying = "NonPaying"
}
struct HelloModel: Codable {
let name: String
let lastName: String
let typeOfCustomer: TypeOfCustomerEnum
}
I would like to reduce the length of init method.
struct Person {
var id: Int
var firstName: String
var lastName: String
var vehicle: String
var location: String
var timeZone: String
init (id: Int, firstName: String, lastName: String, vehicle: String, location: String, timeZone: String ) {
self.firstName = firstName
self.lastName = lastName
self.vehicle = vehicle
self.location = location
self.timeZone = timeZone
}
}
Below is an instance of Person I am creating. I have to pass in the value of every single variable inline.
let person = Person(id: 22, firstName: "John", lastName: "Doe", vehicle: "Chevy", location: "Dallas", timeZone: "CST")
Question: How can I shrink the length of init? In Obj-C I used to create a data model class. Populate it's variables and then pass the entire class, reducing the length of the init method.
i.e.
Person *person = [Person new];
person.id = 22;
person.firstName = "John";
person.lastName = "Doe";
person.vehicle = "Chevy";
person.location = "Dallas";
person.timeZone = "CST"
Person *person = [Person initWithPerson:person];
What's an equivalent way in Swift to reduce the length of init without having to initialize every single variable inline? I know tuples is one way, is there any other best practice?
Just remove the initializer!
struct Person {
let id: Int
let firstName: String
let lastName: String
let vehicle: String
let location: String
let timeZone: String
}
Now you can use the memberwise initializer
Person(
id: 87112,
firstName: "Walter",
lastName: "White",
vehicle: "2004 Pontiac Aztek",
location: "Albuquerque",
timeZone: "UTC-07:00"
)
Structure types automatically receive a memberwise initializer if they do not define any of their own custom initialisers.
The Swift Programming Language
DO NOT use var
As you can see I replaced var with let.
Unless you need to change some properties of a Person after the value has been created, I suggest you to use let. Otherwise you are free to use var. This way the compiler will prevent unwanted changes.
DO NOT use Optionals
I don't know the business logic of your app, however if a Person must have all that 6 properties always populated, don't make them optionals. Otherwise every time you need to use a Person value the compiler will force you to check if that optional has a value.
DO NOT use Implicitly Unwrapped Optionals
Seriously. There are a few cases where they are useful and a model value is not one of them
Using a struct you actually don't need an initializer
struct Person {
var id : Int?
var firstName: String?
var lastName: String?
var vehicle: String?
var location: String?
var timeZone: String?
}
var person = Person()
person.id = 22
person.firstName = "John"
person.lastName = "Doe"
person.vehicle = "Chevy"
person.location = "Dallas"
person.timeZone = "CST"
You can do the same with non-optionals
struct Person {
var id = 0
var firstName = ""
var lastName = ""
var vehicle = ""
var location = ""
var timeZone = ""
}
Consider also the benefit of an initializer to declare (read-only) constants
struct Person {
let id : Int
let firstName : String
let lastName : String
let vehicle : String
let location : String
let timeZone : String
}
In this case you have to use the implicit memberwise initializer.
let person = Person(id: 22, firstName: "John", lastName: "Doe", vehicle: "Chevy", location: "Dallas", timeZone: "CST")
Like it was mentioned in the comments, an initializer will be created for you, and it'll look like this:
Person(id: Int?, firstName: String?, lastName: String?, vehicle: String?, location: String?, timeZone: String?)
However, you can also do this:
var person = Person()
person.id = 100
person.firstName = "Name"
...
Like you used to do in ObjC. Note that person was declared as var, because if it was declared as let, you wouldn't be able to mutate it.