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

Codable Tips集

Codable Tips集

#potatotips 45

0620564f0125b8b3b7f4fe40c10b8b4e?s=128

Tatsuya Tanaka

November 28, 2017
Tweet

Transcript

  1. Codable Tipsू #potatotips 45 ాத ୡ໵ (@tattn)

  2. • Yahoo!৐׵Ҋ಺ • iOSΞϓϦΤϯδχΞ • GitHub: @tattn • Qiita: @tattn

    • Twitter: @tanakasan2525 ాத ୡ໵ (@tattn)
  3. ͓஌Βͤ  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
  4. Codableͱ͸

  5. ܕͷΤϯίʔυͱσίʔυΛαϙʔτ͢Δػೳ  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"}
  6. ܕͷΤϯίʔυͱσίʔυΛαϙʔτ͢Δػೳ  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")
  7. ίίΒ΁ΜΛΈΔͱΘ͔Γ·͢ 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
  8. ·ͣ͸͜ΕΛ఻͍͑ͨ

  9. (´ɾωɾʆ) Swift 3.2Ͱ΋࢖͑ΔΑ (Swift 4͔ΒͷػೳͩͱࢥͬͯΔਓଟ͍ؾ͕͢Δ)

  10. Swift 3.2Ͱ΋࢖͑ΔΑ Xcode 9.0Ҏ্Ͱ͋Ε͹ɺ࢖༻Մೳ Swift 4ʹ·্ͩ͛ΒΕͳ͍൵͍͠ঢ়گͰ΋࢖͑Δ  Swift 4ʹ্͛ΒΕΔ࣌Λ଴ͭඞཁ͸ͳ͍Α

  11. ݟམͱ͕ͪ͠ͳ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
  12. CodableͷTipsू

  13. Key໊͕Swifty͡Όͳ͍

  14. JSONͷkeyͷ಄͕େจࣈ(´ɾωɾʆ)  { "Id": 100, "Name": "Taro" } struct Model:

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

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

    name: String enum CodingKeys: String, CodingKey { case id = "Id" case name = "Name" } } ←typoͦ͠͏
 ɹ৑௕ͳҹ৅ { "Id": 100, "Name": "Taro" }
  17. ͦ͜Ͱ  Upper Camel CaseΛkeyͱ͢Δ
 ϓϩτίϧΛ࡞Δ

  18. 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͕༻ҙ͞Ε͍ͯΔ
  19. 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ͷઌ಄Λখจࣈʹม׵ͯ͠ѻ͏
  20. struct Model: Decodable { let id: Int let name: String

    enum CodingKeys: String, UpperCamelCaseCodingKey { case id case name } } UCCCodingKeyΛ࢖͏  ←ܕͰม׵Λදݱ
 ɹtypo͠ͳ͍ { "Id": 100, "Name": "Taro" }
  21. ͪͳΈʹ  key໊Λtypo͢ΔͱϏϧυΤϥʔʹͯ͘͠ΕΔ 
 (ϝοηʔδ͕෼͔Γʹ͍͚͘Ͳ...)

  22. key໊ͷม׵ΛܕͰදݱ  SnakeCaseCodingKeyͳͲΛඞཁʹԠͯ͡࡞ΕΔ จࣈྻॲཧͷύϑΥʔϚϯε͕ؾʹͳΔ৔߹͸ • ม׵ޙͷkey໊ΛΩϟογϡ͢Δ (᩵୔ʹϝϞϦʹࡌͤΔ) • ίʔυੜ੒͢Δ ↑SourceryΛ࢖͏ͱ࣮ݱͰ͖·͢

    (https://github.com/krzysztofzablocki/Sourcery/)
  23. ΍͍ͤͷ String ͕͋ΒΘΕͨʂ

  24. ΍͍ͤͷ String ͕͋ΒΘΕͨʂ  { "itemId": "1234" } struct Model:

    Decodable { let itemId: String } ඞͣIntʹऩ·Δൣғͷ੔਺ͷidͳͷʹAPI͔ΒจࣈྻͰฦͬͯ͘Δ
 IntͰฦͯ͠΄͍͠Ͱ͢ΑͶ...
  25. ͦ͜Ͱ  StringΛ೚ҙͷܕͰड͚औΕΔ
 ܕΛ࡞Δ (౰ͨΓલͰ͕͢ɺAPIଆΛ௚ͤΔ৔߹͸ͦͷ΄͏͕ྑ͍Ͱ͢)

  26. 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 } }
  27. ຐ๏ͷശΛ࢖͏  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ܕ ↑ܕͰม׵Λදݱ
  28. ஋Λ҆શʹड͚औΓ͍ͨ

  29. ͜Μͳ࣌͋Γ·ͤΜ͔ʁ  ഑ྻ΍URLΛσίʔυ͍͚ͨ͠Ͳɺ
 ͨ·ʹσίʔυͰ͖ͳ͍஋͕ೖΔ

  30. ͦ͜Ͱ  σίʔυͷࣦഊΛ
 ڐ༰͢ΔܕΛ࡞Δ

  31. ջͷ޿͍ܕΛ࡞Δ  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 } } }
  32. ഑ྻΛ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
  33. 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)
  34. ෳ਺ͷϞσϧΛ߹੒͢Δ

  35. ͜Μͳ࣌͋Γ·ͤΜ͔ʁ  ෳ਺ͷϞσϧΫϥεΛ
 1ͭͷϞσϧΫϥεʹ·ͱΊ͍ͨ

  36. ͜Μͳ΋ͷ࡞ͬͯΈ·ͨ͠  https://github.com/tattn/Mergeable

  37. 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)
  38. Mergeable  ཪͰJSONʹͯ͠key/valueΛϚʔδ͢Δͱ͍͏
 ͱͯ΋෋߽తͳ࣮૷ʹͳͬͯ·͢ɻ 
 ։ൃεϐʔυॏࢹͳϋοΧιϯͳͲͰศརͦ͏Ͱ͢ɻ 40ߦఔͷ࣮૷ͳͷͰؾʹͳΔํ͸ಡΜͰΈ͍ͯͩ͘͞

  39. ·ͱΊ

  40. ίʔυ͸͜͜ʹ͋Γ·͢ ࠓճొ৔ͨ͠ίʔυ͸
 ↓ͪ͜Β͔ΒࢀরͰ͖·͢ https://github.com/tattn/CodableExtensionPack

  41. ·ͱΊ ʘૉఢͳܕΛ࡞ͬͯૉఢͳੈքΛ࡞Ζ͏ʗ
 ʘʘ\\٩( 'ω' )و //ʗʗ CodableͰࠔͬͨͱ͖͸
 ಈ࡞ΛΧελϚΠζͨ͠ಠࣗͷܕΛ࡞Δͱ
 ޾ͤʹͳΕ·͢