Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Journey Of Codable

Journey Of Codable

With Codable which got introduced in Swift 4, JSON parsing has become lot easier than it’s ever been before. In this talk, we will trace the journey of Codable, the motivation behind its proposal & understand it's implementation in the swift standard library. We will also explore on how Codable can make developer's life easier through examples ranging from basic to complex ones to understand the flexibility it offers to customize for our use cases.

Bharath Nagaraj Rao

July 28, 2019
Tweet

Other Decks in Programming

Transcript

  1. 1 TB If you want to understand today, you have

    to search yesterday - Pearl S Buck Nobel Laureate 1.2 MB
  2. class Movie { /// Name of the movie let name:

    String /// Director let director: String /// Duration in minutess let duration: Int } Encode <…aea6ffa…> Serialization
  3. class Movie { /// Name of the movie let name:

    String /// Director let director: String /// Duration in minutess let duration: Int } Decode <…aea6ffa…> Serialization
  4. NSCoding Lightweight Obj C protocol #available(iOS 2, *) Supports only

    NSObject types No support for Swift structs, enums No default error handling
  5. Codable extension Movie: Equatable { static func == (lhs: Movie,

    rhs: Movie) -> Bool { return lhs.name == rhs.name && lhs.director == rhs.director && lhs.duration == rhs.duration } } Default implementation by compiler Automatic synthesis of Equatable swift >= 4.1
  6. Codable Default implementation by compiler Automatic synthesis of Equatable swift

    >= 4.1 Automatic synthesis of Hashable extension Movie: Hashable { var hashValue: Int { return name.hashValue ^ director.hashValue ^ duration.hashValue } }
  7. Codable Default implementation by compiler Automatic synthesis of Equatable swift

    >= 4.1 Automatic synthesis of Hashable Automatic codable conformance
  8. Codable types Standard library types Int String Bool Double Float

    Int 8 Int 16 Int 32 Int 64 UInt UInt 8 UInt 16 UInt 32 UInt 64
  9. Codable types %{ codable_types = ['Bool', 'String', 'Double', 'Float', 'Int',

    'Int8', 'Int16', 'Int32', 'Int64', 'UInt', 'UInt8', 'UInt16', 'UInt32', 'UInt64'] }% Standard library types swift/stdlib/public/core/Codable.swift.gyb % for type in codable_types: /// Encodes the given value for the given key. /// /// - parameter value: The value to encode. /// - parameter key: The key to associate the value with. /// - throws: `EncodingError.invalidValue` if the given value is invalid in /// the current context for this format. public mutating func encode(_ value: ${type}, forKey key: Key) throws { try _box.encode(value, forKey: key) } % end
  10. Codable types Standard library types Int UInt Float Double Bool

    String Date Data URL Arrays of Codable types Dictionary of Codable types
  11. Codable public typealias Codable = Encodable & Decodable public protocol

    Decodable { /// Creates a new instance by decoding from the given decoder. /// /// This initializer throws an error if reading from the decoder fails, or /// if the data read is corrupted or otherwise invalid. /// /// - Parameter decoder: The decoder to read data from. init(from decoder: Decoder) throws } public protocol Encodable { /// Encodes this value into the given encoder. /// /// If the value fails to encode anything, `encoder` will encode an empty /// keyed container in its place. /// /// This function throws an error if any values are invalid for the given /// encoder's format. /// /// - Parameter encoder: The encoder to write data to. func encode(to encoder: Encoder) throws }
  12. KeyedDecodingContainer KeyedEncodingContainer Key : Value UnkeyedDecodingContainer UnkeyedEncodingContainer [ CodableType, CodableType,

    CodableType] SingleValueEncodingContainer SingleValueDecodingContainer 123 func container<Key>(keyedBy type: Key.Type) throws -> KeyedDecodingContainer<Key> func unkeyedContainer() throws -> UnkeyedDecodingContainer func singleValueContainer() throws -> SingleValueDecodingContainer Encoder Decoder
  13. import Foundation let jsonString = """ { "name" : "Roma",

    "country" : "Mexico", "director" : "Alfonso Cuarón", "released" : true, "duration" : 135 } “"" guard let jsonData = jsonString.data(using: .utf8) else { fatalError("Check your input & revisit again!") }
  14. struct Movie: Decodable { /// Name of the movie let

    name: String /// Country of origin let country: String /// Director of the movie let director: String /// Release status let released: Bool /// Duration in minutes let duration: Int } do { // That's all folks! let movie = try JSONDecoder().decode(Movie.self, from: jsonData) } catch { print("Exception - \(error.localizedDescription)") }
  15. import Foundation let jsonString = """ { "name" : "Roma",

    "country" : "Mexico", "director" : "Alfonso Cuarón", "released" : true, "duration" : 135 } “"" guard let jsonData = jsonString.data(using: .utf8) else { fatalError("Check your input & revisit again!") }
  16. import Foundation let jsonString = """ { "name" : "Roma",

    "country_name" : "Mexico", "director_name" : "Alfonso Cuarón", “released_status" : true, "duration" : 135 } “"" guard let jsonData = jsonString.data(using: .utf8) else { fatalError("Check your input & revisit again!") }
  17. struct Movie: Decodable { /// Name of the movie let

    name: String /// Country of origin let countryName: String /// Director of the movie let directorName: String /// Release status let releasedStatus: Bool /// Duration in minutes let duration: Int } let decoder = JSONDecoder() decoder.keyDecodingStrategy = .convertFromSnakeCase do { let movie = try decoder.decode(Movie.self, from: jsonData) } catch { print("Exception - \(error.localizedDescription)") }
  18. Custom Coders import XMLParsing let jsonString = """ <movie> <name>Roma</name>

    <country>Mexico</country> <director>Alfonso Cuarón</director> <released>true</released> <duration>135</duration> </movie> """ guard let jsonData = jsonString.data(using: .utf8) else { fatalError("Check your input data & come back again!") } struct Movie: Codable { let name: String let country: String let director: String let released: Bool let duration: Int } do { let movie = try XMLDecoder().decode(Movie.self, from: jsonData) } catch { print("Exception - \(error.localizedDescription)") } Source : https://github.com/ShawnMoore/XMLParsing
  19. public protocol TopLevelDecoder { associatedtype Input func decode<T>(_ type: T.Type,

    from: Self.Input) throws -> T where T : Decodable } extension JSONDecoder: TopLevelDecoder {} Combine
  20. public protocol TopLevelDecoder { associatedtype Input func decode<T>(_ type: T.Type,

    from: Self.Input) throws -> T where T : Decodable } extension JSONDecoder: TopLevelDecoder {} Combine _ = URLSession.shared.dataTaskPublisher(for: request) .tryMap { return $0.data } .decode(type: Movie.self, decoder: JSONDecoder()) .sink(receiveCompletion: { _ in print("Received completion") }, receiveValue: { movie in self.winnerLabel.text = " Best director is \(movie.director)" }) let request = URLRequest(url: URL(string: "https://oscarwinners.org/<directors>")!) import Combine
  21. साधूनां दशर्नं पुण्यं तीथर्भूता िह साधवः I तीथर्ं फलते कालेन

    सद्यः साधुसमागमः II चाणक्यनीित : १२-०८ sādhūnāṃ darśanaṃ puṇyaṃ tīrthabhūtā hi sādhavaḥ I tīrthaṃ phalate kālena sadyaḥ sādhusamāgamaḥ II cāṇakyanīti : 12-08
  22. साधूनां दशर्नं पुण्यं तीथर्भूता िह साधवः I तीथर्ं फलते कालेन

    सद्यः साधुसमागमः II चाणक्यनीित : १२-०८ Meeting scholars is as meritorious as visiting holy places. Fruits of visiting a place is obtained over a period of time but the very sight of scholars/experts brings merit at once.