こんにちは!Apple信者のiOSエンジニアです。
この記事では、SwiftでJSONを扱うためのツール・UnboxとCodableについてお伝えしています。
皆さんは、SwiftでのJSONパーサはなにを使っていますか?
おそらく多くの方がSwift標準のCodableを使っているのではないかなと思います。
しかし実際にiOSエンジニアとしてお仕事をしていると時折、サードパーティライブラリの「Unbox」を使ってJSONパースを行っている記述を見かけます。
先日実際に、プロジェクト内でのパース処理をUnboxからCodableへとお引越しを体験しましたので、そのやり方をこの記事にまとめました。
またCodableがおすすめな理由についても書いていますので、iOSエンジニアの方でCodableについてまだ触ったことがないという方は、ぜひ参考にしていただけたら幸いです!
・UnboxからCodableへの移行を考えている人
・UnboxとCodableの記法を比較検討したい人
Codableとは?
Codableというのは、Swift4からFoundationフレームワークに含められた新しいパース機能です。
API通信などでJSON型のデータを受信した際、アプリ内で取り回すためにカスタムクラスへとパースするときに用いられます。
Unboxとは?
Unboxとは、Codableとは違いサードパーティのJSONデコードライブラリです。
John Sundellさんという方がGitHubに公開していますね。
本家Codableに負けず劣らず、モデル定義から実際の呼び出しまでとてもシンプルに実装を行うことが可能です。
CodableがあるのにUnboxを使うのはどうして?
Appleが公開しているCodableという機能があるのに、どうしてUnboxを使うのかと思われた方もいるかもしれません。
実はSwift標準のCodableが公開されたのは、Swift4から。
なおかつSwift3以前では、Swiftの標準機能だけではJSONパースがとてつもなく面倒でした。
具体的に言うと当時の手法であるNSJSONSerializationというSwift標準のJSONデコーダーは、プログラマ側が指定する処理が雑多。
そのため多くのライブラリ開発者が、Swift向けのJSONパースライブラリを公開していました。
そういったJSONデコーダーのうちの一つが、このUnboxというわけです。
僕の経験からお伝えすれば、Unboxは突出してシンプルで使いやすい印象を受けます。
そのためCodableが登場する前のバージョン3以前のSwiftを用いていたプロジェクトでは、未だにUnboxをそのまま使っている場合も多いわけです。
UnboxからCodableへとパース処理をお引越しさせる方法と注意点
ではここから、実際にUnboxで書かれているパース処理をCodableを用いたものに書き換えていきましょう。
それぞれのモデルクラスと呼び出し処理を示しますので、お引越しではなく比較検討したいという方もぜひ見てみてください。
もしライブラリの導入から行いたい!という方は、こちら「【3分で実装完了!】Swiftの通信ライブラリMoyaの使い方を現役iOSエンジニアがコード付きで教えます!」の記事でXcodeプロジェクトにライブラリを導入する方法について詳しく書いておりますので、一緒に参考にしてみてください。
今回は、言語翻訳APIであるDeepL APIからJSONデータを受け取る様子を例に取ってみます。
ちなみに受け取るJSONデータ構造は、以下のようなものになります。translationsにオブジェクトの配列が入ってくる形ですね。
{
"translations": [{
"detected_source_language":"EN",
"text":"Digital Apple Farm"
}]
}
まずはUnboxでのモデルクラスと、その呼び出し関数についてです。
// Unboxを用いたモデルクラス定義
class UBDeepLModel: Unboxable {
let translations: [UBTranslations]?
required init(unboxer: Unboxer) throws {
translations = try? unboxer.unbox(key: "translations")
}
}
class UBTranslations: Unboxable {
let detectedSourceLangage: String?
let text: String?
required init(unboxer: Unboxer) throws {
detectedSourceLangage = try? unboxer.unbox(key: "detected_source_language")
text = try? unboxer.unbox(key: "text")
}
}
// Unboxを用いたパースの呼び出し処理
let ubDeepLModel: UBDeepLModel? = try? unbox(data: data!)
以上が、Unboxでの記述ですね。
では今度は、同じ記述をCodableを使ったものに書き換えていきましょう。
// Codableを用いたモデルクラス定義
struct DeepLModel: Codable {
let translations: [Translations]
}
struct Translations: Codable {
let detectedSourceLanguage: String
let text: String
private enum CodingKeys: String, CodingKey {
case detectedSourceLanguage = "detected_source_language"
case text
}
}
// Codableを用いたパースの呼び出し処理
let deepLModel = try? JSONDecoder().decode(DeepLModel.self, from: data!)
上記が、Codableを用いた呼び出し処理となります。
どうでしょうか?
お互いに「モデル定義から1行でインスタンスへの格納完了」と簡潔な処理であるため、引っ越し作業も全く難しくありませんね。
CodableのCodingKeyについて
先程のコードには、以下のような記述があったと思います。
private enum CodingKeys: String, CodingKey {
case detectedSourceLanguage = "detected_source_language"
case text
}
これはCodableに定義されている記法で、CodingKeysと呼ばれるものです。
受け取ったJSON型に含まれるKeyと、アプリ側で期待しているKeyが異なる場合に用います。
上記の例で言えば、
- JSONに含まれるキーは「detected_source_language」とスネークケース
- アプリ側で期待している変数は「detectedSourceLanguage」とローワーキャメルケース
ですね。
コーディング規約でアプリ側でスネークケース禁止だったり、JSONのKeyが似たようなものが多く複雑だったりした場合に、このCodingKeysが大活躍します。
Codableへの移行作業を行う上での注意点
ただ作業自体は難しいものではありませんが、アプリによってはたくさんのAPI通信用のモデルを定義している場合もあります。
たとえば僕が担当したアプリには、100以上のAPIモデルがありました。
そのためモデルクラスが多い場合には、一気に移し替えるというよりも、僕の経験上少しずつ移行していくとスムーズだと感じましたよ。
UnboxからCodableへと乗り換えるべき理由
Unboxはとても便利で、作られたOSS開発者の方は素晴らしくスマートだと感じています。
ただ特段の理由がない場合には、できるだけSwift標準のCodableでパース処理を行うことがおすすめ。
その理由について、詳しく解説していきますね。
記述がシンプルで楽
Codableを使うことによるメリットは、まず記述がとにかくシンプルだということ。
Unboxでパース処理を行う場合には、変数とは別にJSONのKeyの値をString型ですべて定義する必要があります。
そのため凄まじい量のKey/Valueを返すようなJSONでは、かなりのストレスになってしまいますよね。
その点Codableでは、JSONのキーと同じ変数名を定義する限りにおいては、Keyを自前で文字列として用意する必要はありません。
JSONのキー名とモデルクラスの変数名を異なるものにする場合にこそ、先程お伝えしたCodingKeyの記述が要りますが、それ以外は自動的にCodableでパースが出来てしまうんです。
アップデートへのリスクを最小限に抑えるため
Unboxはシンプルに使える素晴らしいライブラリ。
少なくとも僕の経験上、2022年1月時点では、度重なる環境アップデートでも問題なく使用できています。
しかしながら、環境アップデートによるライブラリへの影響はiOSエンジニアにとって悩みの種の一つですよね。
なのでCodableを使うべきもう一つの理由としては、やはりSwiftやXcodeのアップデートの影響を抑えるためだと僕は思いますよ。
念には念を入れて、時間のあるときに純正の機能へと移行を済ませてしまうというのもリスク対策の一つといえるでしょう。
さいごに
この記事では、JSONパースライブラリのUnboxをSwift標準機能のCodableへと置き換える方法などをお伝えしてきました。
個人的には、Unboxは使いやすくてとても大好きです!
Codableに備わっているCodingKeysは、初学のうち理解と実装に手間取りましたが、その点Unboxはすごくわかりやすいと感じるんです。
そのため、適材適所でUnboxとCodableを使い分けていくのもいいかもしれませんね。
この記事が、Codableへの移行を考えている方のお役に立てたなら幸いです。