使用 NSCoding 保存结构
Posted
技术标签:
【中文标题】使用 NSCoding 保存结构【英文标题】:Save a struct with NSCoding 【发布时间】:2018-06-16 12:33:41 【问题描述】:我要保存以下数据:
class Book: NSObject, NSCoding
var title: String
var chapter: [Chapter]
struct Chapter
var chapTitle: String
var texte: [Texte]
struct Texte
var description: String
var texte: [String]
var position: [Int]
var hidden: [Int?]
我目前正在使用 NSCoder 来保存 Book 类:
static let DocumentsDirectory = FileManager().urls(for: .documentDirectory, in: .userDomainMask).first!
static let ArchiveURL = DocumentsDirectory.appendingPathComponent("learn")
struct PropertyKey
static let title = "title"
static let chapter = "Chapter"
//MARK: - Initialization
init?(title: String, chapter: [Book.Chapter])
self.title = title
self.chapter = chapter
//MARK: - NSCoding
func encode(with aCoder: NSCoder)
aCoder.encode(title, forKey: PropertyKey.title)
aCoder.encode(chapter, forKey: PropertyKey.chapter)
required convenience init?(coder aDecoder: NSCoder)
let title = aDecoder.decodeObject(forKey: PropertyKey.title) as! String
let chapter = aDecoder.decodeObject(forKey: PropertyKey.chapter) as! [Book.Chapter]
self.init(title: title, chapter: chapter)
有了这个,我可以保存 Book 的 title
和一个空数组 chapter
。
但是,当我尝试将 chapTitle
和 texte
添加到 Book 对象时,出现以下错误:
由于未捕获的异常“NSInvalidArgumentException”而终止应用程序,原因:'-[SwiftValue encodeWithCoder:]:无法识别的选择器发送到实例 0x60000066dec0'
这是否意味着该结构无法保存?我应该改变什么?
【问题讨论】:
当你可以在 Swift 4 中使用Codable
时,为什么要使用旧的 NSCoding
协议?
你不能因为一个结构它不是一个类因此它不能从 NSObject 继承
您有两个选择。如果要使用结构,请使用类而不是结构或使用 Codable 协议
【参考方案1】:
如果你可以让 book 成为 struct ,你最好使用 codable 。
struct Book: Codable
var title: String
var chapter: [Chapter]
struct Chapter:Codable
var chapTitle: String
var texte: [Texte]
struct Texte:Codable
var description: String
var texte: [String]
var position: [Int]
var hidden: [Int?]
保存
static func saveData (books: [Book]) throws
let encoded = try JSONEncoder().encode(books)
try encoded.write(to: ArchiveURL)
print("Books saved")
检索
//retrive data from it's saved place
static func loadData() throws -> [Book]
let data = try Data(contentsOf: ArchiveURL)
return try JSONDecoder().decode([Book].self, from: data)
同时编辑顶部的变量
let directory = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] + "/learn/"
let ArchiveURL = URL(fileURLWithPath: directory)
【讨论】:
我尝试使用 Codable,但是当我尝试从 URL 加载数据时,它返回nil
。这是我使用的代码:SAVE:static func saveData (books: [Book]) guard let encoded = try? JSONEncoder().encode(books) else return //To user defaults or what ever you choose try? encoded.write(to: ArchiveURL) print("Books saved")
加载:static func loadData() -> [Book]? let data = ArchiveURL.absoluteURL.dataRepresentation let parsedData = try? JSONDecoder().decode([Book].self, from: data) return parsedData
您的加载和保存功能错误,我在更新的答案中包含了两个,请测试一下。
忽略错误 (try?
) 并通过 FileManager
加载数据不是一个好建议。将这两个函数设为throw
,在load
函数中返回一个非可选函数,并使用let data = try Data(contentsOf: directoryURL)
加载数据,因为无论如何您都在处理一个URL。
@vadian:正确。当我使用let data = try Data(contentsOf: directoryURL)
加载数据时,它运行良好。 throw
函数还允许我识别数据保存中的错误。以上是关于使用 NSCoding 保存结构的主要内容,如果未能解决你的问题,请参考以下文章
将 Codable 保存到 UserDefaults 并匹配 NSCoding 的外观