我试图在我的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。如果taskArraynil,则程序将崩溃。

使用条件解包会更安全,也可以使用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,而不是对象。

由于isImportantBool,所以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

10-08 06:28