💨

AppStorageにCodableを保存する時に気を付けたいパフォーマンスの話

2024/05/14に公開

AppStorageにオブジェクトを保存する場合、CodableとRawRepresentableの組み合わせを使ってJSONのStringとして保存するテクニックがあります。

https://zenn.dev/ikeh1024/articles/bd7dcf28e38f3c

非常に強力なのですが、この実装部分でUIスレッドがハングする問題に当たったので原因と解決策を紹介します。

原因と解決策

SwiftUIでは、差分検知のためにEquatableが使われます。
Equatableは、その構造体が持つすべてのプロパティがEquatableであればそれらを連結した結果を自身の等価判定に利用します。

しかし、RawRepresentable, Equatableの場合、Equatableの実装はrawValueを比較するように実装されています。

https://github.com/apple/swift/blob/ab57ef9bbeccc85aa31903c583ad0edb849a9b70/stdlib/public/core/CompilerProtocols.swift#L152

これによって、値の比較が行われるたびにCodableの重いデコード・エンコード処理が行われUIスレッドをハングさせていたというわけです。

この問題はEquatableを自前で実装することで回避することができます。

struct Session: RawRepresentable, Equatable {
    ...

    public static func == (lhs: Self, rhs: Self) -> Bool {
        lhs.id == rhs.id
    }
}

Discussion