You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI中如何为Codable+ObservableObject类添加自定义初始化器

实现同时支持Codable、@Published的自定义初始化类

要实现你需要的功能,核心是在继承ObservableObject并遵循Codable的类中,通过便捷初始化器实现User("Bob Smith")的调用方式,同时满足Codable要求的required初始化器规则。以下是完整实现方案:

完整代码示例

import SwiftUI

class User: ObservableObject, Codable {
    // @Published属性,支持响应式更新,可作为EnvironmentObject传递
    @Published var name: String
    
    // Codable要求的required解码初始化器(手动实现,因为自定义了其他初始化器)
    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        name = try container.decode(String.self, forKey: .name)
    }
    
    // Codable要求的编码方法
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(name, forKey: .name)
    }
    
    // 自定义便捷初始化器,实现User("Bob Smith")的调用方式
    convenience init(_ name: String) {
        self.init(name: name)
    }
    
    // 基础初始化器,供便捷初始化器调用,也可直接使用
    init(name: String) {
        self.name = name
    }
    
    // 定义Codable字段映射
    enum CodingKeys: String, CodingKey {
        case name
    }
}

关键逻辑说明

  1. 继承与协议:类必须继承ObservableObject才能使用@Published,同时遵循Codable以支持@AppStorage存储。
  2. Codable初始化器:由于自定义了初始化器,编译器无法自动合成Codable的解码/编码逻辑,因此需要手动实现required init(from decoder:)和encode(to:),并通过CodingKeys枚举映射属性与JSON字段。
  3. 自定义初始化器:使用convenience关键字定义便捷初始化器,它会调用基础初始化器init(name:),既满足required初始化器的规则(子类需实现该初始化器),又实现了你需要的简洁调用方式。

使用场景示例

1. 创建实例

let user = User("Bob Smith")
print(user.name) // 输出:Bob Smith

2. 作为EnvironmentObject传递

struct ContentView: View {
    @StateObject var user = User("Bob Smith")
    
    var body: some View {
        ChildView()
            .environmentObject(user)
    }
}

struct ChildView: View {
    @EnvironmentObject var user: User
    
    var body: some View {
        Text(user.name)
    }
}

3. 存入@AppStorage

@AppStorage直接存储Codable类型需要转换为Data,通过JSON编解码实现:

struct SettingsView: View {
    @AppStorage("user") private var userData: Data?
    @StateObject var user = User("Bob Smith")
    
    var body: some View {
        VStack {
            Button("保存用户") {
                let encoder = JSONEncoder()
                if let data = try? encoder.encode(user) {
                    userData = data
                }
            }
            
            Button("加载用户") {
                guard let data = userData, 
                      let loadedUser = try? JSONDecoder().decode(User.self, from: data) 
                else { return }
                user.name = loadedUser.name
            }
        }
    }
}

内容的提问来源于stack exchange,提问作者Stoic

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 23:11:14