Simplifying Data Serialization in Swift: Exploring Codable for iOS Development — Part 2

Simplifying Data Serialization in Swift: Exploring Codable for iOS Development — Part 2

By? Vinodhkumar Govindaraj , Senior iOS Developer at?Evangelist Apps.

Previously:

Simplifying Data Serialization in Swift: Exploring Codable for iOS Development — Part 1

Encoding and Decoding Dates in Swift’s Codable:

When using dates in Swift’s?Codable, you can encode and decode them using the?Date type. By default,?Date?is encoded as a timestamp representing the number of seconds since January 1, 1970.

Example of encoding and decoding dates in Swift:

struct Event: Codable {
    var title: String
    var date: Date
}

let event = Event(title: "Meeting", date: Date())

let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .iso8601 // Set the date encoding strategy to ISO 8601 format
if let encodedData = try? encoder.encode(event),
   let jsonString = String(data: encodedData, encoding: .utf8) {
    print(jsonString)
}

let json = """
    {"title":"Conference","date":"2023-05-27T10:30:00Z"}
"""
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601 // Set the date decoding strategy to ISO 8601 format
if let jsonData = json.data(using: .utf8),
   let decodedEvent = try? decoder.decode(Event.self, from: jsonData) {
    print(decodedEvent.title)
    print(decodedEvent.date)
}        

In the example, we use a?Event?struct with?title?and?date?properties. To encode the date in JSON, we set the `JSONEncoder`’s date encoding strategy to?.iso8601, which formats the date as?“2023–05–27T10:30:00Z”?(ISO 8601 format). This format is widely supported.

Similarly, when decoding from JSON, we set the?JSONDecode's?date decoding strategy to?.iso8601?to ensure the ISO 8601-formatted date string is correctly parsed into a `Date` object.

Swift offers different date encoding and decoding strategies, including?.formatted(_:),?.millisecondsSince1970, and?.secondsSince1970. Choose the strategy that suits your requirements.

For custom date formats or non-standard representations, create a custom date formatter and assign it to the encoder’s?dateEncodingStrategy?and decoder’s?dateDecodingStrategy?properties.

By configuring the date encoding and decoding strategies, you can accurately handle dates in?Codable?operations in Swift.

Handling an Array with Mixed Types using Custom Enums in Swift’s Codable:

To handle an array with mixed types in Swift’s?Codable, create a custom enum representing the possible types within the array. Each enum case corresponds to a specific type, enabling you to encode and decode the array seamlessly. Consider the following example:

enum MixedType: Codable {
    case string(String)
    case int(Int)
    case bool(Bool)

    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if let value = try? container.decode(String.self) {
            self = .string(value)
        } else if let value = try? container.decode(Int.self) {
            self = .int(value)
        } else if let value = try? container.decode(Bool.self) {
            self = .bool(value)
        } else {
            throw DecodingError.typeMismatch(MixedType.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Invalid type"))
        }
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch self {
        case .string(let value):
            try container.encode(value)
        case .int(let value):
            try container.encode(value)
        case .bool(let value):
            try container.encode(value)
        }
    }
}

struct MixedArray: Codable {
    var items: [MixedType]
}

let array = MixedArray(items: [.string("John Doe"), .int(30), .bool(true)])

let encoder = JSONEncoder()
if let encodedData = try? encoder.encode(array),
   let jsonString = String(data: encodedData, encoding: .utf8) {
    print(jsonString) // Output: {"items":["John Doe",30,true]}
}

let json = """
    {"items":["Jane Smith",42,false]}
"""
let decoder = JSONDecoder()
if let jsonData = json.data(using: .utf8),
   let decodedArray = try? decoder.decode(MixedArray.self, from: jsonData) {
    for item in decodedArray.items {
        switch item {
        case .string(let value):
            print("String:", value)
        case .int(let value):
            print("Int:", value)
        case .bool(let value):
            print("Bool:", value)
        }
    }
}        

In the example above, we define a?MixedType?enum that represents string, integer, and boolean values. To enable encoding and decoding, we implement the?Codable?protocol by providing the?init(from:)?and?encode(to:)?methods.

In the?init(from:)?method, we decode a single value from the decoder using a?singleValueContainer(). We sequentially attempt to decode the value as a?String,?Int, and?Bool, assigning the appropriate enum case accordingly.

In the?encode(to:)?method, we use a?singleValueContainer()?to encode the enum case based on its type.

The?MixedArray?struct contains an array of?MixedType?elements, which can be encoded and decoded successfully.

Strategies for Handling Cases in Codable: Key Conversions Made Easy

To handle different cases in Swift’s?Codable, you can use the?keyDecodingStrategy?and?keyEncodingStrategy?properties of?JSONDecoder?and?JSONEncoder. These properties specify the conversion strategy between Swift property names and JSON keys.

There are three built-in strategies available:

  1. useDefaultKeys: Assumes property names in Swift match JSON keys exactly (default).
  2. convertFromSnakeCase: Converts snake case JSON keys (e.g. ,?“first_name”) to camel case (e.g.,?firstName).
  3. convertToSnakeCase: Converts camel case property names (e.g.,?firstName) to snake case JSON keys (e.g.,“first_name”).

Here’s an example using different case strategies in?Codable:

struct Person: Codable {
    var firstName: String
    var lastName: String
}

let json = """
{
    "first_name": "John",
    "last_name": "Doe"
}
"""

let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
if let jsonData = json.data(using: .utf8),
   let person = try? decoder.decode(Person.self, from: jsonData) {
    print(person.firstName) // Output: John
    print(person.lastName) // Output: Doe
}

let encoder = JSONEncoder()
encoder.keyEncodingStrategy = .convertToSnakeCase
if let encodedData = try? encoder.encode(person),
   let jsonString = String(data: encodedData, encoding: .utf8) {
    print(jsonString) // Output: {"first_name":"John","last_name":"Doe"}
}        

In the given example, we have a?Person?struct with?firstName?and?lastName?properties. To handle the conversion between JSON keys and property names, we utilize the?keyDecodingStrategy?of the?JSONDecoder?and set it to?.convertFromSnakeCase. This strategy converts snake case JSON keys (e.g.,?“first_name”) to camel case property names (e.g., firstName) during decoding.

During the decoding process, the JSON key?“first_name”?is mapped to the?firstName?property, and?“last_name”?is mapped to the?lastNameproperty.

Similarly, we set the?keyEncodingStrategy?of the?JSONEncoder?to?.convertToSnakeCase. This strategy converts camel case property names to snake case JSON keys when encoding to JSON. As a result, the generated JSON will have“first_name”?and?“last_name”?as the respective keys.

By utilizing the appropriate case conversion strategies, Codable allows seamless handling of different cases between Swift types and JSON keys.

Conclusion:

Codable offers a convenient way to work with data serialization in Swift, simplifying the process of converting Swift types to and from various formats.

Hope you enjoyed reading this article.

Cheers!

#swift #swiftui #ios #composablearchitecture

要查看或添加评论,请登录

Evangelist Apps的更多文章

社区洞察

其他会员也浏览了