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

Codable Tips集

Codable Tips集

#potatotips 45

Tatsuya Tanaka

November 28, 2017
Tweet

More Decks by Tatsuya Tanaka

Other Decks in Technology

Transcript

  1. ͓஌Βͤ  Yahoo! JAPAN Tech Advent Calendar 2017
 https://qiita.com/advent-calendar/2017/yahoojapan-tech ↑11೔ʹCI/CDͷ࿩Λॻ͖·͢


    ↓ଞʹ΋iosͱswiftͷΞυϕϯτΧϨϯμʔʹࢀՃͯ͠·͢ https://qiita.com/advent-calendar/2017/swift https://qiita.com/advent-calendar/2017/ios
  2. ܕͷΤϯίʔυͱσίʔυΛαϙʔτ͢Δػೳ  struct User: Codable { let id: String let

    name: String } let encoder = JSONEncoder() let user = User(id: "abc", name: "Taro") let data = try! encoder.encode(user) let json = try! JSONSerialization.jsonObject( with: data, options: .allowFragments ) print(json) // {"id": "abc", "name": "Taro"}
  3. ܕͷΤϯίʔυͱσίʔυΛαϙʔτ͢Δػೳ  struct User: Codable { let id: String let

    name: String } let json = """ {"id": "abc", "name": "Taro"} """.data(using: .utf8)! let decoder = JSONDecoder() let user = try! decoder.decode(User.self, from: data) print(user) // User(id: "abc", name: "Taro")
  4. ίίΒ΁ΜΛΈΔͱΘ͔Γ·͢ Swift 4 Codable by Yasuhiro Inami Swift 4͔Β࣮૷͞ΕΔCodable/codable_in_foundation_with_swift4 by

    fromkk Codableͷinit(from:)ΛͲ͏ॻ͔͘ by takasek Swift4.0 Ͱ௥Ճ͞ΕΔ Codable - Qiita Codableʹ͍ͭͯ৭ʑ·ͱΊͨ[Swift4] - Qiita IUUQTTQFBLFSEFDLDPNJOBNJZTXJGUDPEBCMF IUUQTTQFBLFSEFDLDPNGSPNLLDPEBCMFJOGPVOEBUJPOXJUITXJGU IUUQTRJJUBDPNIBOBXBUJUFNTG⒎GBDBFBFB IUUQTRJJUBDPN@IBGJUFNTCGBBEFBFGGE IUUQTTQFBLFSEFDLDPNUBLBTFLOVNCFSXXEDFCJTV IUUQTEFWFMPQFSBQQMFDPNEPDVNFOUBUJPOGPVOEBUJPOBSDIJWFT@BOE@TFSJBMJ[BUJPOFODPEJOH@BOE@EFDPEJOH@DVTUPN@UZQFT Encoding and Decoding Custom Types
  5. ݟམͱ͕ͪ͠ͳSwift 3.2Ͱ࢖͑Δػೳ ෳ਺ߦจࣈྻϦςϥϧ  let str = """ Θʔ͍ʋ(ʆ▽´)/ ෳ਺ߦͷจࣈྻϦςϥϧ͕

    ॻ͚ΔΑʔʘʘ\\٩( 'ω' )و //ʗʗ """ class Hoge: NSObject { dynamic var value = 0 } let hoge = Hoge() let token = hoge.observe(\.value) { (object, change) in print(object.value) } KeyPathϦςϥϧͱΫϩʔδϟܕKVO
  6. JSONͷkeyͷ಄͕େจࣈ(´ɾωɾʆ)  { "Id": 100, "Name": "Taro" } struct Model:

    Decodable { let id: Int let name: String } ←͜͏͍͚ͨ͠Ͳ
 ɹͰ͖ͳ͍ɻɻ (ϓϩύςΟ໊ͱkey໊͕Ұக͍ͯ͠ͳ͍ͨΊ)
  7. ී௨ͷରԠํ๏  struct Model: Decodable { let id: Int let

    name: String enum CodingKeys: String, CodingKey { case id = "Id" case name = "Name" } } ←CodingKeysͰ
 ɹϓϩύςΟ໊ͱରԠ෇͚ { "Id": 100, "Name": "Taro" }
  8. ී௨ͷରԠํ๏  struct Model: Decodable { let id: Int let

    name: String enum CodingKeys: String, CodingKey { case id = "Id" case name = "Name" } } ←typoͦ͠͏
 ɹ৑௕ͳҹ৅ { "Id": 100, "Name": "Taro" }
  9. CodingKey ϓϩτίϧ  public protocol CodingKey { public var stringValue:

    String { get } public init?(stringValue: String) public var intValue: Int? { get } public init?(intValue: Int) } CodingKeyʹ͸key໊ͱϓϩύςΟ໊ͷରԠΛ
 ΧελϚΠζͰ͖ΔI/F͕༻ҙ͞Ε͍ͯΔ
  10. UCCͳkeyΛѻ͏protocolΛ࡞Δ  protocol UpperCamelCaseCodingKey: CodingKey {} extension UpperCamelCaseCodingKey where Self:

    RawRepresentable, Self.RawValue == String { var stringValue: String { return String(rawValue.prefix(1).capitalized + rawValue[rawValue.index(after: rawValue.startIndex)...]) } } keyͷઌ಄Λখจࣈʹม׵ͯ͠ѻ͏
  11. struct Model: Decodable { let id: Int let name: String

    enum CodingKeys: String, UpperCamelCaseCodingKey { case id case name } } UCCCodingKeyΛ࢖͏  ←ܕͰม׵Λදݱ
 ɹtypo͠ͳ͍ { "Id": 100, "Name": "Taro" }
  12. ΍͍ͤͷ String ͕͋ΒΘΕͨʂ  { "itemId": "1234" } struct Model:

    Decodable { let itemId: String } ඞͣIntʹऩ·Δൣғͷ੔਺ͷidͳͷʹAPI͔ΒจࣈྻͰฦͬͯ͘Δ
 IntͰฦͯ͠΄͍͠Ͱ͢ΑͶ...
  13. StringΛผͷܕʹม׵͢Δຐ๏ͷശ  struct StringTo<T: LosslessStringConvertible>: Decodable { let value: T

    init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() let stringValue = try container.decode(String.self) guard let value = T(stringValue) else { throw DecodingError.dataCorrupted( .init(codingPath: decoder.codingPath, debugDescription: "ʘ(^o^)ʗ") ) } self.value = value } }
  14. ຐ๏ͷശΛ࢖͏  let json = """ { "itemId": "1234" }

    """.data(using: .utf8)! struct Model: Decodable { let itemId: StringTo<Int> } let model = try! decoder.decode(Model.self, from: json) print(model.itemId.value) // value͸Intܕ ↑ܕͰม׵Λදݱ
  15. ջͷ޿͍ܕΛ࡞Δ  struct Safe<Wrapped: Decodable>: Decodable { let value: Wrapped?

    init(from decoder: Decoder) throws { do { let container = try decoder.singleValueContainer() self.value = try container.decode(Wrapped.self) } catch { self.value = nil } } }
  16. ഑ྻΛSafeͰแΉ  let json = """ [ {"name": "Taro", "age":

    20}, {"name": "Hanako", "age": "ʹΌʔΜ"} ] """.data(using: .utf8)! struct User: Decodable { let name: String let age: Int } let users = try! JSONDecoder().decode([Safe<User>].self, from: json) users[0].value // User(name: "Taro", age: 20) users[1].value // nil
  17. URLΛSafeͰแΉ  let json = """ {"url": "https://foo.com", "url2": "urlͰ͸ͳ͍จࣈྻ"}

    """.data(using: .utf8)! struct Model: Decodable { let url: Safe<URL> let url2: Safe<URL> } let model = try! JSONDecoder().decode(Model.self, from: json) // Model(url: Safe<URL>(value:Optional(https://foo.com)), url2: Safe<URL>(value: nil)) model.url.value // Optional(https://foo.com)
  18. https://github.com/tattn/Mergeable  struct APIResponse: Codable { let id: Int let

    title: String let foo: String } struct APIResponse2: Codable { let tags: [String] } struct Model: Codable, Mergeable { let id: Int let title: String let tags: [String] } let response = APIResponse(id: 0, title: "ʹΌʔΜ", foo: "bar") let response2 = APIResponse2(tags: ["swift", "ios", "macos"]) let model = try! Model.merge(response, response2) XCTAssertEqual(model.id, response.id) XCTAssertEqual(model.title, response.title) XCTAssertEqual(model.tags, response2.tags)