使用可选的初始化程序将自定义数据类型存储在 @AppStorage 中?

nic*_*rno 11 nsuserdefaults swift swiftui

我正在尝试将自定义数据类型存储到AppStorage. 为此,模型符合RawRepresentable(遵循本教程)。它工作正常,但是当我初始化@AppStorage变量时,它需要一个初始UserModel值。我想让该变量可选,因此如果用户注销,它可以为零。这可能吗?

在类/视图中,我可以这样初始化:

@AppStorage("user_model") private(set) var user: UserModel = UserModel(id: "", name: "", email: "")
Run Code Online (Sandbox Code Playgroud)

但我想这样初始化:

@AppStorage("user_model") private(set) var user: UserModel?
Run Code Online (Sandbox Code Playgroud)

模型:

struct UserModel: Codable {
        
    let id: String
    let name: String
    let email: String
    
    enum CodingKeys: String, CodingKey {
        case id
        case name
        case email
    }
    
    init(from decoder: Decoder) throws {        
        let values = try decoder.container(keyedBy: CodingKeys.self)
        
        do {
           id = try String(values.decode(Int.self, forKey: .id))
        } catch DecodingError.typeMismatch {
           id = try String(values.decode(String.self, forKey: .id))
        }
        self.name = try values.decode(String.self, forKey: .name)
        self.email = try values.decode(String.self, forKey: .email)
    }
    
    init(id: String, name: String, email: String) {
        self.id = id
        self.name = name
        self.email = email
    }
    
}

// MARK: RAW REPRESENTABLE

extension UserModel: RawRepresentable {
    
    // RawRepresentable allows a UserModel to be store in AppStorage directly.
    
    public init?(rawValue: String) {
        guard let data = rawValue.data(using: .utf8),
            let result = try? JSONDecoder().decode(UserModel.self, from: data)
        else {
            return nil
        }
        self = result
    }

    var rawValue: String {
        guard let data = try? JSONEncoder().encode(self),
            let result = String(data: data, encoding: .utf8)
        else {
            return "[]"
        }
        return result
    }
    
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(id, forKey: .id)
        try container.encode(name, forKey: .name)
        try container.encode(email, forKey: .email)
    }
    
}
Run Code Online (Sandbox Code Playgroud)

mar*_*kiv 9

任何可选的可能的通用方法Codable

extension Optional: RawRepresentable where Wrapped: Codable {
    public var rawValue: String {
        guard let data = try? JSONEncoder().encode(self) else {
            return "{}"
        }
        return String(decoding: data, as: UTF8.self)
    }

    public init?(rawValue: String) {
        guard let value = try? JSONDecoder().decode(Self.self, from: Data(rawValue.utf8)) else {
            return nil
        }
        self = value
    }
}
Run Code Online (Sandbox Code Playgroud)

完成此操作后,现在可以将任何内容 Codable保留在应用程序存储中:

@AppStorage("user_model") var user: UserModel? = nil
Run Code Online (Sandbox Code Playgroud)


paw*_*222 6

下面的代码可以工作,因为您添加了一致性UserModel: RawRepresentable

@AppStorage("user_model") private(set) var user: UserModel = UserModel(id: "", name: "", email: "")
Run Code Online (Sandbox Code Playgroud)

UserModel?如果您希望以下内容起作用,您需要执行相同的操作:

@AppStorage("user_model") private(set) var user: UserModel? = nil
Run Code Online (Sandbox Code Playgroud)

这是一个可能的解决方案:

extension Optional: RawRepresentable where Wrapped == UserModel {
    public init?(rawValue: String) {
        guard let data = rawValue.data(using: .utf8),
              let result = try? JSONDecoder().decode(UserModel.self, from: data)
        else {
            return nil
        }
        self = result
    }

    public var rawValue: String {
        guard let data = try? JSONEncoder().encode(self),
              let result = String(data: data, encoding: .utf8)
        else {
            return "[]"
        }
        return result
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: UserModel.CodingKeys.self)
        try container.encode(self?.id, forKey: .id)
        try container.encode(self?.name, forKey: .name)
        try container.encode(self?.email, forKey: .email)
    }
}
Run Code Online (Sandbox Code Playgroud)

注意:我重复使用了您已经拥有的实现UserModel: RawRepresentable- 对于这种情况可能需要一些更正。

另外,因为你顺从,所以你也Optional: RawRepresentable需要公开 UserModel