11
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

SwiftでCodableの実装を爆速でする方法

Posted at

はじめに

  • サーバとの通信処理ではResponseの値をmappingやparseして、Swiftで扱いやすいように変換する処理をよく書きます。JSONからSwiftの値に変換するときにはCodableを使うと楽に実装できます。そんなCodableの実装もAPIが増えるごとにたくさん実装、メンテする必要がでてきます。そんな実装を爆速でするための方法について、まとめました。

JSONの型とSwiftで使う型の変換

{ "name": "Tanaka", "age": "26", "gender": "0" }
  • このようなJSONあるときに実装で扱いやすい型に変換するときに苦労した経験があります。(String <-> Intの変換など)
    Codableで逐次変換処理を書くと可読性が落ちて、メンテし辛いコードが出来上がります。それを克服するためにDTOを使って、可読性の高いコードにしてみます。

DTOを使ったCodableの処理

DTOとは

  • Data Transfer Objectを省略したものです。

  • Layer間の値の受け渡しに使います。

  • このJSONをSWiftの値に変換する処理を書いてみます。

{ "name": "Tanaka", "age": "26", "gender": "0" }
  • before
    • 普通に書くとtry の処理と型変換の処理がたくさん書くことになります
import UIKit

let json = """
{ "name": "Tanaka", "age": "26", "gender": "0" }
""".data(using: .utf8)!

enum Gender: Int {
    case male = 0
    case female
    case unknown
}

struct Person {
    let name: String
    let age: Int
    let gender: Gender
    
    enum CodingKeys: String, CodingKey {
        case name
        case age
        case gender
    }
}
enum DecodableError: Error {
    case ageError
    case genderError
}

extension Person: Decodable {
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        name = try container.decode(String.self, forKey: .name)
        let ageValue = try container.decode(String.self, forKey: .age)
        guard let age = Int(ageValue) else {
            throw DecodableError.ageError
        }
        self.age = age
        
        let genderString = try container.decode(String.self, forKey: .gender)
        guard let genderValue = Int(genderString), let gender = Gender(rawValue: genderValue) else {
            throw DecodableError.genderError
        }
        self.gender = gender
    }
}

let decoder = JSONDecoder()
let person = try decoder.decode(Person.self, from: json)
  • after
    • DTODecodableを使って、tryの処理を書かなくていいようにします。DTOではJSONで宣言されている型の通りに変換することで値のparseのみ行います。Entity側ではDTOの値を元にEntityで必要な型に変換します。Entity側ではtryの処理を意識しないのでコードの可読性が上がりました。

import UIKit

protocol DTODecodable: Decodable {
    associatedtype DTO: Decodable
    init(dto: DTO) throws
}

extension DTODecodable {
    init(from decoder: Decoder) throws {
        let dto = try DTO(from: decoder)
        self = try Self.init(dto: dto)
    }
}

let json = """
{ "name": "Tanaka", "age": "26", "gender": "0" }
""".data(using: .utf8)!

enum Gender: Int {
    case male = 0
    case female
    case unknown
}

struct Person {
    let name: String
    let age: Int
    let gender: Gender
    
    enum CodingKeys: String, CodingKey {
        case name
        case age
        case gender
    }
}

extension Person: DTODecodable {
    struct DTO: Decodable {
        let name: String
        let age: String
        let gender: String
    }
    
    init(dto: DTO) throws {
        self.name = dto.name
        guard let age = Int(dto.age) else {
            throw DTODecodableError.ageError
        }
        
        guard let genderValue = Int(dto.gender),
              let gender = Gender(rawValue: genderValue) else {
            throw DTODecodableError.genderError
        }
        
        self.age = age
        self.gender = gender
    }
    
    enum DTODecodableError: Error {
        case ageError
        case genderError
    }
}

let decoder = JSONDecoder()
let person = try decoder.decode(Person.self, from: json)
  • 実装イメージ

Untitled Diagram.png

Codableのコードを生成する

  • ここでは2つのツールについて紹介します。2つともJSONを元にCodableの実装を生成するツールです。

  • quicktype

    • WebでJSONからCodableの実装が生成されます
  • YutoMizutani/JSONtoCodable

    • JSONtoCodableを使うとCodableの実装が生成されます

Kapture 2020-12-04 at 18.21.51.gif

まとめ

  • DTOを使うことでCodableの可読性があがります。
  • 生成ツールを使うとさらに爆速で開発できます

参考リンク

11
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?