Swift3 使用NSCoding保存带有自定义对象的数组

Swift3 使用NSCoding保存带有自定义对象的数组,swift3,ios10,Swift3,Ios10,我正在制作一个待办事项列表应用程序来了解细节,它有一个简单的列表和项目结构。我使用3个类来管理它们: ToDomainManager:是一个单例,用于集中管理我的视图控制器中的列表和列表中的项。它包含一个todolist数组和一组函数,用于添加列表、将它们标记为已完成列表并返回列表 TodoList:有一个字符串变量(name)、bool变量(completed)和一个TodoItems数组 TodoItem:具有字符串变量(名称)和布尔变量(已完成) 我想存储我的自定义对象数组[TodoL

我正在制作一个待办事项列表应用程序来了解细节,它有一个简单的列表和项目结构。我使用3个类来管理它们:

  • ToDomainManager:是一个单例,用于集中管理我的视图控制器中的列表和列表中的项。它包含一个todolist数组和一组函数,用于添加列表、将它们标记为已完成列表并返回列表
  • TodoList:有一个字符串变量(name)、bool变量(completed)和一个TodoItems数组
  • TodoItem:具有字符串变量(名称)和布尔变量(已完成)
我想存储我的自定义对象数组[TodoList],以便以后可以加载它,我正在寻找世界上最简单的方法。UserDefaults不允许自定义对象(因为它是用于设置的),所以我需要使用NSCoding持久化数据,为此我需要让TodoList类从NSObjects继承

class TodoManager: NSObject, NSCoding {
    // the singleton
    static let shared = TodoManager()

    // filePath var
    private var filePath : String {
        let url = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
        return url.appendingPathComponent("objectsArray").path
    }

    // init
    override private init() {}

    // array to store all lists
    private var lists = [TodoList]()

    func newTodoList(title: String) {
        lists.append(TodoList(instanceTitle: title))
    }

    // coding
    func encode(with coder: NSCoder) {
        coder.encode(lists, forKey: "lists")
    }

    required convenience init(coder decoder: NSCoder) {
        self.init()
        lists = decoder.decodeObject(forKey: "lists") as! [TodoList]
    }

    // saving and loading
    func saveAll() {
        let data = lists
        NSKeyedArchiver.archiveRootObject(data, toFile: filePath)
    }

    func loadAll() {
        if let dataArray = NSKeyedUnarchiver.unarchiveObject(withFile: filePath) as? [TodoList] {
            lists = dataArray
        }
    }
}

class TodoList: NSObject, NSCoding {
    // array to store items in this list instance
    private var items = [TodoItem]()

    // vars to store title and completion status
    private var title = String()
    private var completed = Bool()

    // init
    init(instanceTitle: String) {
        title = instanceTitle
        completed = false
    }

    // coding
    func encode(with coder: NSCoder) {
        coder.encode(items, forKey: "lists")
        coder.encode(title, forKey: "title")
        coder.encode(completed, forKey: "completed")
    }

    required convenience init(coder decoder: NSCoder) {
        self.items = decoder.decodeObject(forKey: "items") as! [TodoItem]
        self.title = decoder.decodeObject(forKey: "title") as! String
        self.completed = decoder.decodeBool(forKey: "completed")
        self.init() // <----- critical line
    }

    // item-related
    func addItem(title: String) {
        items.append(TodoItem(instanceTitle: title))
    }
}

class TodoItem: NSObject, NSCoding {
    private var title = String()
    private var completed = Bool()


    // inits
    init(instanceTitle: String) {
        title = instanceTitle
        completed = false
    }

    func encode(with coder: NSCoder) {
        coder.encode(title, forKey: "title")
        coder.encode(completed, forKey: "completed")
    }

    required convenience init(coder decoder: NSCoder) {
        self.init() // <----- similar critical line
        title = decoder.decodeObject(forKey: "title") as! String
        completed = decoder.decodeBool(forKey: "completed")
    }
}
类ToDomainManager:NSObject,NSCoding{ //单身汉 静态let shared=ToDomainManager() //文件路径变量 私有变量文件路径:字符串{ 让url=FileManager.default.url(对于:.documentDirectory,在:.userDomainMask中)。首先! 返回url.appendingPathComponent(“objectsArray”).path } //初始化 重写私有init(){} //数组来存储所有列表 私有变量列表=[TodoList]() func新代码列表(标题:字符串){ lists.append(TodoList(instanceTitle:title)) } //编码 func编码(带编码器:NSCoder){ 编码(列表,forKey:“列表”) } 所需便利初始化(编码器-解码器:NSCoder){ self.init() lists=decoder.decodeObject(forKey:“lists”)为![TodoList] } //保存和加载 func saveAll(){ 让数据=列表 归档对象(数据,toFile:filePath) } func loadAll(){ 如果让dataArray=NSKeyedUnarchiver.unarchiveObject(带文件:filePath)作为?[TodoList]{ 列表=数据数组 } } } 类TodoList:NSObject,NSCoding{ //数组来存储此列表实例中的项 私有变量项=[TodoItem]() //存储标题和完成状态的变量 私有变量title=String() private var completed=Bool() //初始化 init(instanceTitle:String){ title=instanceTitle 已完成=错误 } //编码 func编码(带编码器:NSCoder){ 编码器编码(项目,forKey:“列表”) 编码员编码(标题,福基:“标题”) 编码器编码(已完成,forKey:“已完成”) } 所需便利初始化(编码器-解码器:NSCoder){ self.items=decoder.decodeObject(forKey:“items”)as![TodoItem] self.title=decoder.decodeObject(forKey:“title”)作为!字符串 self.completed=decoder.decodeBool(forKey:“completed”)
self.init()//调用便利的
初始值设定项()
时,实际参数最初传递给指定的
init()
由请求创建类的新实例的函数调用,无需通过便利初始化。您可以使用占位符调用指定的初始值设定项,该占位符在执行时填充。对于我的情况,它如下所示:

init(instanceTitle: String) {
    title = instanceTitle
    completed = false
}

required convenience init(coder decoder: NSCoder) {
    // call designated init
    self.init(instanceTitle: "[placeholder]")
    items = decoder.decodeObject(forKey: "items") as! [TodoItem]
    title = decoder.decodeObject(forKey: "title") as! String
    completed = decoder.decodeBool(forKey: "completed")
}