我试图在我的userdefaults中保存一个类的实例,我已经使用以下方法这样做,并且在我的类中添加isImportant属性后,它似乎不起作用。
这是我的代码
class Task: NSObject , NSCoding {
var taskDate:String
var task:String
var isImportant:Bool
init(task: String , taskDate: String , isImportant: Bool){
self.task = task
self.taskDate = taskDate
self.isImportant = isImportant
}
required convenience init?(coder aDecoder: NSCoder) {
guard let taskDate = aDecoder.decodeObject(forKey: "taskDate") as? String ,
let task = aDecoder.decodeObject(forKey: "task") as? String ,
let importantdecode = aDecoder.decodeObject(forKey: "importantBool") as? Bool else {
return nil
}
self.init(task: task, taskDate: taskDate , isImportant:importantdecode)
}
func encode(with aCoder: NSCoder) {
aCoder.encode(taskDate, forKey: "taskDate")
aCoder.encode(task, forKey: "task")
aCoder.encode(isImportant, forKey: "importantBool")
}
}
上面的代码是我的课程,我添加了一些协议,老实说,我不知道它们如何正常工作。
现在这就是我面临的问题。
var tasks = [Task]()
let defaults = UserDefaults.standard
let defaultskey:String = "save"
et task:Task = Task(task: taskTextField.text!, taskDate: now ,isImportant: false )
tasks.append(task)
// Calling the saveTask Function
saveTasks()
// Calling the shake function in the custombutton class since we declared the sender here to be CustomButtom
sender.shake()
}
override func viewDidLoad() {
super.viewDidLoad()
// Getting the permanent Storage
loadTasks()
// Saving array of objects with userDefaults
func saveTasks() {
do {
let taskDataWorking = try NSKeyedArchiver.archivedData(withRootObject: tasks, requiringSecureCoding: false) // archiving data for object to be able to store it.
defaults.set(taskDataWorking, forKey: defaultskey)
//throw MyError.FoundNil("xmlDict")
} catch {
print(error)
}
}
// Loading the data
func loadTasks(){
let taskData = defaults.object(forKey: defaultskey) as? NSData
if let taskData = taskData {
do {
let taskArray = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(taskData as Data) as? [Task] // unarchiving data as and loading it
** The error occurs here ** tasks = taskArray! // assigning the tasks to the archived value when saved so when it launched we will be back at the last saved tasks
tasksAccomplished = taskArray!.count
} catch {
print("error while loading")
}
}
}
最佳答案
崩溃的表面原因是:
let taskArray = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(taskData as Data) as? [Task]
tasks = taskArray!
您强行打开可选的
taskArray
。如果taskArray
是nil
,则程序将崩溃。使用条件解包会更安全,也可以使用nil合并运算符提供默认值。
if let taskArray = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(taskData as Data) as? [Task] {
tasks = taskArray
} else {
// Unable to load tasks - do something
}
要么
let taskArray = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(taskData as Data) as? [Task]
tasks = taskArray ?? []
真正的问题是,为什么初始化程序失败?为什么
taskArray
为零?答案就在这一行:
let importantdecode = aDecoder.decodeObject(forKey: "importantBool") as? Bool else {
return nil
}
键
importantBool
用于编码Bool,而不是对象。由于
isImportant
是Bool
,所以aCoder.encode(isImportant, forKey: "importantBool")
调用encode(_ value: Bool, forKey: String)
。可能会造成混乱。由于Swift知道您要编码的值的类型,因此可以调用正确的
encode
。解码时,它不知道与密钥关联的类型。您有责任调用正确的decode...
函数。你要
guard let taskDate = aDecoder.decodeObject(forKey: "taskDate") as? String ,
let task = aDecoder.decodeObject(forKey: "task") as? String else {
return nil
}
let importantDecode = aDecoder.decodeBool(forKey: "importantBool")
self.init(task: task, taskDate: taskDate , isImportant:importantdecode)
请注意,与
decodeObject
不同,decodeBool
不会返回可选内容,因此它不能成为guard
语句的一部分。您仍应进行防御性编码,而不要强行打开
taskArray
。