我正在创建一个待办事项列表应用程序来学习输入和输出,它有一个简单的列表项目结构。我使用3个类来管理它们:
我想存储我的自定义对象数组[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")
}
}
我遇到的问题是,在easy init中,instanceTitle是未声明的,因此我无法将其传递给self.init()。我无法将声明添加到所需的便利init,因为它将错误该类不符合所需的协议。我尝试了很多变化,但经过几个小时的盯着这个并使用我的谷歌foo我无法弄明白。我在NSCoding的兔子洞里做错了什么?
答案 0 :(得分:0)
当调用便捷initializer()
时,由请求新类实例的函数最初传递给指定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")
}