使用 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

但是,当我尝试将 chapTitletexte 添加到 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 保存结构的主要内容,如果未能解决你的问题,请参考以下文章

使用 NSCoding 保存结构的 Helperclass

将 Codable 保存到 UserDefaults 并匹配 NSCoding 的外观

使用 NSCoding 保存 TableView 单元格的重新排序

无法通过 NSCoding 保存表数据

保存 PFObject NSCoding

使用 NSCoding Swift 保存对象时出现异常