Share
Embed
Transcript
41 slides
-
• Yahoo!Ҋ • iOSΞϓϦΤϯδχΞ • GitHub: @tattn • Qiita: @tattn
• Twitter: @tanakasan2525 ాத ୡ (@tattn) -
͓Βͤ 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 -
ܕͷΤϯίʔυͱσίʔυΛαϙʔτ͢Δػೳ 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"} -
ܕͷΤϯίʔυͱσίʔυΛαϙʔτ͢Δػೳ 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") -
ίίΒΜΛΈΔͱΘ͔Γ·͢ 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 -
ݟམͱ͕ͪ͠ͳ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 -
JSONͷkeyͷ಄͕େจࣈ(´ɾωɾʆ) { "Id": 100, "Name": "Taro" } struct Model:
Decodable { let id: Int let name: String } ←͜͏͍͚ͨ͠Ͳ ɹͰ͖ͳ͍ɻɻ (ϓϩύςΟ໊ͱkey໊͕Ұக͍ͯ͠ͳ͍ͨΊ) -
ී௨ͷରԠํ๏ struct Model: Decodable { let id: Int let
name: String enum CodingKeys: String, CodingKey { case id = "Id" case name = "Name" } } ←CodingKeysͰ ɹϓϩύςΟ໊ͱରԠ͚ { "Id": 100, "Name": "Taro" } -
ී௨ͷରԠํ๏ struct Model: Decodable { let id: Int let
name: String enum CodingKeys: String, CodingKey { case id = "Id" case name = "Name" } } ←typoͦ͠͏ ɹͳҹ { "Id": 100, "Name": "Taro" } -
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͕༻ҙ͞Ε͍ͯΔ -
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ͷઌ಄Λখจࣈʹมͯ͠ѻ͏ -
struct Model: Decodable { let id: Int let name: String
enum CodingKeys: String, UpperCamelCaseCodingKey { case id case name } } UCCCodingKeyΛ͏ ←ܕͰมΛදݱ ɹtypo͠ͳ͍ { "Id": 100, "Name": "Taro" } -
key໊ͷมΛܕͰදݱ SnakeCaseCodingKeyͳͲΛඞཁʹԠͯ͡࡞ΕΔ จࣈྻॲཧͷύϑΥʔϚϯε͕ؾʹͳΔ߹ • มޙͷkey໊ΛΩϟογϡ͢Δ (᩵ʹϝϞϦʹࡌͤΔ) • ίʔυੜ͢Δ ↑SourceryΛ͏ͱ࣮ݱͰ͖·͢
(https://github.com/krzysztofzablocki/Sourcery/) -
͍ͤͷ String ͕͋ΒΘΕͨʂ { "itemId": "1234" } struct Model:
Decodable { let itemId: String } ඞͣIntʹऩ·ΔൣғͷͷidͳͷʹAPI͔ΒจࣈྻͰฦͬͯ͘Δ IntͰฦͯ͠΄͍͠Ͱ͢ΑͶ... -
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 } } -
ຐ๏ͷശΛ͏ 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) // valueIntܕ ↑ܕͰมΛදݱ -
ջͷ͍ܕΛ࡞Δ 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 } } } -
ྻΛ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 -
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) -
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)