【SwiftUI】ObservedObjectをCodableにする方法

ObservedObjectと@Publishedプロパティラッパーは、Classを監視して値(プロパティ)が変更されたらViewを再描画します。

ただし、UserDefaultで保存するためにクラスをCodableに準拠しておくと、@Publishedを付けた時に以下のエラーが出ました。

このエラーを解決するには、以下の通り、デコードとエンコードを実装すると解決します。

class Gym:Identifiable,Codable,ObservableObject {
    
    // Publishedのプロパティラッパーをつける場合、decodeアクションとencodeアクションが必要になる。
    @Published var id:UUID
    @Published var Menu:String
    @Published var WeightString:String
    @Published var KaisuString:String
    @Published var SetsuString:String

    init(Menu:String,WeightString:String,KaisuString:String,SetsuString:String) {
        self.id = UUID()
        self.Menu = Menu
        self.WeightString = WeightString
        self.KaisuString = KaisuString
        self.SetsuString = SetsuString
    }
    
    /// ①変換対象プロパティ指定
    enum CodingKeys: CodingKey {
        case id
        case Menu
        case WeightString
        case KaisuString
        case SetsuString
    }

    /// ②プロパティのdecode(復号化)アクション
    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        id = try container.decode(UUID.self, forKey: .id)
        Menu = try container.decode(String.self, forKey: .Menu)
        WeightString = try container.decode(String.self, forKey: .WeightString)
        KaisuString = try container.decode(String.self, forKey: .KaisuString)
        SetsuString = try container.decode(String.self, forKey: .SetsuString)
    }

    /// ③プロパティのencode(コード化)アクション
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(id, forKey: .id)
        try container.encode(Menu, forKey: .Menu)
        try container.encode(WeightString, forKey: .WeightString)
        try container.encode(KaisuString, forKey: .KaisuString)
        try container.encode(SetsuString, forKey: .SetsuString)
    }
}