将变量添加到已保存的用户默认值变量 创建一个 protected 变量:

如何解决将变量添加到已保存的用户默认值变量 创建一个 protected 变量:

我下载了一个快速文件,应该可以帮助我保存和加载自定义变量:

import Foundation

protocol ObjectSavable {
func setToObject<Object>(_ object: Object,forKey: String) throws where Object: Encodable
func getToObject<Object>(forKey: String,castTo type: Object.Type) throws -> Object where Object: Decodable
}

extension UserDefaults: ObjectSavable {
func setToObject<Object>(_ object: Object,forKey: String) throws where Object: Encodable {
    let encoder = JSONEncoder()
    do {
        let data = try encoder.encode(object)
        set(data,forKey: forKey)
    } catch {
        throw ObjectSavableError.unableToEncode
    }
}

func getToObject<Object>(forKey: String,castTo type: Object.Type) throws -> Object where Object: Decodable {
    guard let data = data(forKey: forKey) else { throw ObjectSavableError.noValue }
    let decoder = JSONDecoder()
    do {
        let object = try decoder.decode(type,from: data)
        return object
    } catch {
        throw ObjectSavableError.unableToDecode
    }
}
}

enum ObjectSavableError: String,LocalizedError {
case unableToEncode = "Unable to encode object into data"
case noValue = "No data object found for the given key"
case unableToDecode = "Unable to decode object into given type"
}

我有这个Person结构:

struct Person: Encodable,Decodable {
    var firstName: String
    var lastName: String
    var birthday: Date

    init() {
        self.firstName = "Tim"
        self.lastName = "Cook"
        self.birthday = Date()
    }
}

我也有这段代码用于保存/加载Person结构(正在使用上面的代码)

保存:

print("Saving object...")
    let person: Person = Person()
    
    do {
        try UserDefaults.standard.setToObject(person,forKey: "person")
        print("Object saved successfully")
    } catch let err {
        print("Error while saving object:\n\(err.localizedDescription)")
    }

正在加载:

print("Loading object...")
    
    do {
        self.person = try UserDefaults.standard.getToObject(forKey: "person",castTo: Person.self)
        print("Successfully load object:\n\(self.person!)")
    } catch let err {
        print("Error while loading object:\n\(err.localizedDescription)")
    }

现在,所有这些都有效。 但是,假设我以这种方式发布了我的应用,然后我想向Person添加一个新变量,例如,我将添加一个favorite

struct Person: Encodable,Decodable {
    var firstName: String
    var lastName: String
    var birthday: Date
    var favorite: Bool = false

    init() {
        self.firstName = "Tim"
        self.lastName = "Cook"
        self.birthday = Date()
    }
}

在更新之前,应用程序(在favorite中没有Person变量)将被保存,而没有favorite变量。更新之后,应用程序将尝试使用Person变量加载先前保存的favorite。这就是失败的原因,因为较旧版本的数据中没有favorite变量。因此会引发错误。

我的问题是,有没有办法在从用户默认值中解码Person时,如果找不到任何匹配的变量(例如:favorite),而不是抛出错误,它将尝试自动创建吗? (来自var favorite = false )?

我的项目:https://github.com/orihpt/Encodable

谢谢。

解决方法

一种方法是将自定义解码代码添加到Person中:

enum CodingKeys : CodingKey {
    case firstName
    case lastName
    case birthday
    case favorite
}

init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    firstName = try container.decode(String.self,forKey: .firstName)
    lastName = try container.decode(String.self,forKey: .lastName)
    birthday = try container.decode(Date.self,forKey: .birthday)
    favorite = try container.decodeIfPresent(Bool.self,forKey: .favorite) ?? false
}

请注意,对于favorite,我使用了decodeIfPresent,默认值为false


另一种方法是将favorite声明为可选:

var favorite: Bool?

如果数据中不存在favorite,而不是您想要的nil中没有false,则会将其设置为false。如果您确实想要Bool?,则可以使用一个隐式解包的可选nil,并且每次解码时都需要将false更改为self.person = try UserDefaults.standard.getToObject(forKey: "person",castTo: Person.self) if self.person.favorite == nil { self.person.favorite = false }

getToObject

如果您担心自己可能会忘记这样做,可以使protocol HasDefaults { func changeNilsToDefaults() } extension UserDefaults { func getToObject<Object: HasDefaults>(forKey: String,castTo type: Object.Type) throws -> Object where Object: Decodable { guard let data = data(forKey: forKey) else { throw ObjectSavableError.noValue } let decoder = JSONDecoder() do { let object = try decoder.decode(type,from: data) object.changeNilsToDefaults() // notice this line! return object } catch { throw ObjectSavableError.unableToDecode } } } 仅接受符合此协议的对象:

getToObject(forKey: "person",castTo: Person.self)

除非您使Person符合HasDefaults,否则您将无法执行extension Person : HasDefaults { func changeNilsToDefaults() { if self.person.favorite == nil { self.person.favorite = false } } }

{{1}}
,

@Sweeper的建议是可行的解决方案。您还可以将其“可选”方法与DTO解决方案合并。

DTO: Data transfer object

将对象另存为DTO对象,并在首次发行后将新属性添加为“可选”:

struct PersonDTO: Codable {
    let firstName: String
    let lastName: String
    let birthday: Date
    let favorite: Bool?
}

从UserDefaults获取DTO对象后,使用它初始化您的Person对象。

struct Person {
    var firstName: String
    var lastName: String
    var birthday: Date
    var favorite: Bool

    init(_ dto: PersonDTO) {
        self.firstName = dto.firstName
        self.lastName = dto.lastName
        self.birthday = dto.birthday
        self.favorite = dto.favorite ?? false
    }
}
,

创建一个 protected 变量:

struct Person: Encodable,Decodable {
    var firstName: String
    var lastName: String
    var birthday: Date
    var favorite: Bool {
        get {
            return favoriteProtected ?? false
        }
        set {
            favoriteProtected = newValue
        }
    }

    private var favoriteProtected: Bool? = nil

    init() {
        self.firstName = "Tim"
        self.lastName = "Cook"
        self.birthday = Date()
    }
}

这样您就不必实施 init(from decoder: Decoder),如果您的 struct 很大,这可能需要很长时间。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res