🕷️

グッバイ!JSONModel

2023/09/28に公開

こんにちは、スペースマーケットでモバイルエンジニアをしている村田です。

スペースマーケットゲストiOSプロジェクトの言語使用率はSwift 96.2%、Objective-C 3.6%とまだまだレガシーコードが残っている状態です。主にAPI通信/ModelにObj-C製のものが残留しており、日々の業務タスクをこなしつつSwiftへの置き換えを進めています(自分が入社した当時は7%以上残っていたので1.5年で半分程度は消えました🙏)

JSONデータからObj-C製モデルへの変換ライブラリとして JSONModel を使用していましたが、タイトルの通り今回削除対応しました。その理由や削除する上で大変だったことを本記事で共有できればと思います。

削除のきっかけ

7月頃に「予約詳細画面に何も表示されない」と問い合わせがあり、確認したところiOS17β端末で予約情報取得後のJSONModelによるマッピングが失敗していることが判明しました。穴を塞ぐ作業はすぐに行い不具合解消したバージョンをリリースしたのですが、今後のOSアップデートで他モデルも同様なエラーが発生する可能性があり使用し続けるリスクが大きいため、iOS17リリースまでにJSONModel削除する事を決断しました(実際 β5あたりでレビュー一覧画面で同様のエラーが発生していました)

JSONModelとは

改めてJSONModelとは、JSONデータからObj-C製モデルオブジェクトにマッピングするためのライブラリです。自分はSwiftから入った人間でスペースマーケットに入社するまで扱ったことなかったのですが、Objective-Cを触っていた方からするとメジャーなライブラリの1つですかね?
最新リリースはv1.7.0の2016年でした🧟

https://github.com/jsonmodel/jsonmodel#basic-usage

洗い出し

まず、以下をFigmaへ洗い出しました。

  • JSONModelのどの機能を利用しているか(JSONパーサー以外にも機能があり)
  • モデルのリレーション

洗い出した結果、他モデルへの依存がない&JSONModelのメソッドほぼ使っていないモデルはそもそもObj-C脱却できるなと判断してSwift化しました(4モデルSwift化できました🙌)

JSONModelの以下メソッドを利用しており、それぞれ必要であれば各モデルに自作しました。

  • initWithString: JSON形式の文字列を解析、モデルオブジェクトにマッピング
  • initWithDictionary: NSDictionary型のデータを元にオブジェクトを生成
  • toJSONString: オブジェクトをJSON形式の文字列に変換
  • toDictionary: オブジェクトをNSDictionary型へ変換

initWithDictionary自作

ルーム情報のモデルである SMRoom へ作成したものを例に、ほぼ全てのモデルで必要なinitWithDictionaryメソッドの置き換え対応について記載します。
(因みに、削除しかしたことなかったので今回の対応で初めてObj-Cコード書きました)

まずヘッダファイルへメソッド宣言追加。

SMRoom.h
@protocol SMRoom;
@interface SMRoom : SMModel
@property (nonatomic, strong, nonnull) NSNumber *id;
@property (nonatomic, strong, nonnull) NSString *uid;
@property (nonatomic, strong, nullable) NSString *name;
⁝
(省略)
⁝
@property (nonatomic, strong, nullable) SMSpace *space;
@property (nonatomic, strong, nullable) SMOwner *owner;

+ (nonnull SMRoom *)initWithDictionary:(nonnull NSDictionary*)dictionary;

@end

次に実装ファイルへメソッドを定義。
引数のdictionaryからキーに対応する値を取得し、各プロパティへ設定します。
(これを計17モデルへ実装。かなり骨が折れました...)

SMRoom.m
#import "SMRoom.h"

@implementation SMRoom

+ (SMRoom *)initWithDictionary:(NSDictionary*)dictionary {
    SMRoom *room = [[SMRoom alloc] init];

    room.id = dictionary[@"id"];
    room.uid = dictionary[@"uid"];
    room.name = dictionary[@"name"];
    ⁝
    (省略)
    ⁝
    room.owner = [SMOwner initWithDictionary:dictionary[@"owner"]];
    room.space = [SMSpace initWithDictionary:dictionary[@"space"]];

    return room;
}

NSNull対応

key値に対応する値がnullの場合NSNullを返却するため、Swift側でそのまま扱おうとした際にクラッシュしてしまいました(そもそもkeyが存在しない場合はnilを返すようでした)。
一律nilとして扱いたいため、NSNullの場合はnilを返却するメソッドをNSDictionaryへ生やして対応。

NSDictionary+Extensions.m
#import "NSDictionary+Extensions.h"

@implementation NSDictionary (Extensions)
- (nullable id)objectOrNilForKey:(nonnull NSString*)key {
    id object = [self objectForKey:key];
    if (object == [NSNull null] || object == nil) {
        return nil;
    } else {
        return object;
    }
}
@end
SMRoom.m
#import "SMRoom.h"
#import "NSDictionary+Extensions.h"

@implementation SMRoom

+ (SMRoom *)initWithDictionary:(NSDictionary*)dictionary {
    SMRoom *room = [[SMRoom alloc] init];

    room.id = dictionary[@"id"];
    room.uid = dictionary[@"uid"];
    room.name = [dictionary objectOrNilForKey:@"name"];
    ⁝
    (省略)
    ⁝
    if ([dictionary objectOrNilForKey:@"owner"] != nil) {
        room.owner = [SMOwner initWithDictionary:dictionary[@"owner"]];
    }
    if ([dictionary objectOrNilForKey:@"space"] != nil) {
        room.space = [SMSpace initWithDictionary:dictionary[@"space"]];
    }

    return room;
}

@end

振り返り

スペースマーケットのスクラムは1週間スプリントで動いています。
他のタスクもやりつつという事もあり、約2ヶ月(8スプリント)かかりました...。

差分3000行を超え、コミット数は190でした(PRは不具合修正対応込みで26個)
レビューも大変だったと思います。メンバーに感謝!!!

アプリ全体に関わる大規模な対応だったのでリリース怖かったですが、今の所致命的な不具合はなさそうです。

※ 是非アプリインストールよろしくお願いします!問題あればご報告もいただければ嬉しいです

iOS Android

感想

プロジェクトへがっつり絡んだライブラリの削除はかなり大変でした。更新が長らく止まっているライブラリは「動いていることが奇跡」と考えて徐々に剥がしていくよう早めの動きだしが必要ですね...。
削除予定のライブラリは他にもDeprecatedになったAFNetworking、そのSwift版であるAlamofire、Combine登場により不要になりつつあるRx系。UI周りもKLCPopupなど古いもの幾つか利用しており、徐々にSwiftUI化しつつ消していければと考えています。

大変ですが自らの手で不要なものを消して数が減っていくことに喜び感じてます。幻影旅団2人狩った際のヒソカと同じ気分です。


出典:漫画「HUNTER×HUNTER」

「あと 10ライブラリ......♪」

最後に

ヒソカの気分になりたいあなた、スペースマーケットでは一緒に働く仲間を募集中です!
詳しくは以下をご確認の上ご応募ください。

https://spacemarket.co.jp/recruit/engineer/

https://www.wantedly.com/projects/1061116

https://www.wantedly.com/projects/1113570

https://www.wantedly.com/projects/1113544

GitHubで編集を提案
スペースマーケット Engineer Blog

Discussion