xcode - 使用 NSKeyedArchiver 保存枚举和嵌套数组
问题描述
作为初学者,我发现持久数据存储是一项艰巨的挑战。在使用 Core Data 和 SQLite 并没有取得多大成功之后,我终于找到了一个使用 NSKeyedArchiver 的好例子。但现在我需要扩展它以包括枚举和嵌套数组。
首先,我尝试仅添加枚举,但在保存过程中失败。
在下面的代码中,我还尝试添加嵌套数组,但这会使 IDE 崩溃。
没有颜色枚举和 STARS 嵌套数组的简化版本工作得很好。
//
// ViewController.swift
//
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
//Create a test object
let myPlanets1 = [PlanetStruct(name: "Earth", isHabitable: true), PlanetStruct(name: "Mars", isHabitable: false)]
let myStar1 = StarStruct(name: "Sun", PLANETS: myPlanets1)
let myPlanets2 = [PlanetStruct(name: "Herculis", isHabitable: true), PlanetStruct(name: "Delphini", isHabitable: false), PlanetStruct(name: "Librae", isHabitable: false)]
let myStar2 = StarStruct(name: "Rigel", PLANETS: myPlanets2)
let myStorage = StorageUnit(heading: "test", items: ["Arthur", "Ford", "Trillian", "Zaphod", "Marvin"], numbers: [[1, 2, 3],[4, 5, 6]], color: ColorEnum.red, stars: [myStar1, myStar2])
print("Created: \(String(describing: myStorage.heading))")
//Where to save?
let DocumentsDirectory = FileManager().urls(for: .documentDirectory, in: .userDomainMask).first!
let ArchiveURL = DocumentsDirectory.appendingPathComponent("storageunit")
//Save test object
do {
let data = try NSKeyedArchiver.archivedData(withRootObject: myStorage, requiringSecureCoding: false)
try data.write(to: ArchiveURL)
} catch {
print("Couldn't write file")
}
//Load data into a new object
let codedData = try? Data(contentsOf: ArchiveURL)
var RestoredStorage = StorageUnit(heading: "", items: [], numbers: [[]], color: ColorEnum.red, stars: [])
do {
if let loadedObject = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(codedData!) as? StorageUnit {
RestoredStorage = loadedObject
}
} catch {
print("Couldn't read file.")
}
//Print loaded data for verification
print("Loaded: \(String(describing: RestoredStorage.heading))")
}
}
struct PlanetStruct {
var name : String
var isHabitable : Bool
}
struct StarStruct {
var name : String
var PLANETS : [PlanetStruct]
}
enum ColorEnum : Int { case red, yellow, blue }
class StorageUnit: NSObject, NSCoding {
var heading : String
var items : [String]
var numbers: [[Int]]
var color : ColorEnum
var STARS : [StarStruct]
struct PropertyKey {
static let headingKey = "heading"
static let itemsKey = "items"
static let numbersKey = "numbers"
static let colorKey = "color"
static let starKey = "stars"
}
required convenience init(coder aDecoder: NSCoder) {
let heading = aDecoder.decodeObject(forKey: PropertyKey.headingKey) as! String
let items = aDecoder.decodeObject(forKey: PropertyKey.itemsKey) as! [String]
let numbers = aDecoder.decodeObject(forKey: PropertyKey.numbersKey) as! [[Int]]
let stars = aDecoder.decodeObject(forKey: PropertyKey.starKey) as! [StarStruct]
let color = aDecoder.decodeObject(forKey: PropertyKey.colorKey) as! ColorEnum
self.init(heading: heading, items: items, numbers: numbers, color: color, stars: stars)
}
init(heading: String, items : [String], numbers: [[Int]],color: ColorEnum, stars: [StarStruct]) {
self.heading = heading
self.items = items
self.numbers = numbers
self.color = color
self.STARS = stars
super.init()
}
func encode(with aCoder: NSCoder) {
aCoder.encode(heading, forKey: PropertyKey.headingKey)
aCoder.encode(items, forKey: PropertyKey.itemsKey)
aCoder.encode(numbers, forKey: PropertyKey.numbersKey)
aCoder.encode(color, forKey: PropertyKey.colorKey)
aCoder.encode(STARS, forKey: PropertyKey.starKey)
}
}
解决方案
感谢 Codable 的提示。
与往常一样,我发现的示例与 Swift5 不直接兼容......
但是下面的这段代码对我有用:-) 不过可能需要在错误处理上做一些工作。
//
// ViewController.swift
//
import UIKit
class ViewController: UIViewController {
var MYDATA = DataStruct(owner: "", STARS: [])
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
// Make some test data
let PLANETS1 = [PlanetStruct(name: "Earth", isHabitable: true), PlanetStruct(name: "Mars", isHabitable: false)]
let PLANETS2 = [PlanetStruct(name: "Herculis", isHabitable: true), PlanetStruct(name: "Delphini", isHabitable: false), PlanetStruct(name: "Librae", isHabitable: false)]
let STAR1 = StarStruct(name: "Sun", PLANETS: PLANETS1, color: ColorEnum.red)
let STAR2 = StarStruct(name: "Rigel", PLANETS: PLANETS2, color: ColorEnum.blue)
let MYDATA = DataStruct(owner: "Bob", STARS: [STAR1, STAR2])
// Where to save?
let DocumentsDirectory = FileManager().urls(for: .documentDirectory, in: .userDomainMask).first!
let ArchiveURL = DocumentsDirectory.appendingPathComponent("mydata")
// Save data
SaveData(myDataStruct: MYDATA, FileURL: ArchiveURL)
print("Saved data: \(MYDATA.owner)")
// Load data
let LOADED = LoadData(FileURL: ArchiveURL)
print("Loaded data: \(LOADED?.owner ?? "Failed")" )
print("Loaded data: \(LOADED?.STARS[1].PLANETS[0].name ?? "Failed")" )
}
func SaveData(myDataStruct: DataStruct, FileURL : URL) {
do {
let propertylist = try PropertyListEncoder().encode(myDataStruct)
let data = try NSKeyedArchiver.archivedData(withRootObject: propertylist, requiringSecureCoding: false )
try data.write(to: FileURL)
} catch {
print("Save failed")
}
}
func LoadData(FileURL : URL ) -> DataStruct? {
if let data = try? Data(contentsOf: FileURL) {
do {
let propertylist = (try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? Data)!
let loadedData = try PropertyListDecoder().decode(DataStruct.self, from: propertylist)
return loadedData
} catch {
print("Load failed")
}
}
//Return empty
return nil
}
}
enum ColorEnum : Int, Codable { case red, yellow, blue }
struct PlanetStruct : Codable {
var name : String = ""
var isHabitable : Bool = false
}
struct StarStruct : Codable {
var name : String = ""
var PLANETS : [PlanetStruct]
var color : ColorEnum
}
struct DataStruct : Codable {
var owner : String = ""
var STARS : [StarStruct]
}
推荐阅读
- python - Pandas 按列分组并创建带有结果的字典
- apache-flink - 在本地模式下更改 Apache Flink 绑定地址
- c - 功率递归程序 - 效率
- optimization - 如何对具有绝对约束的最小二乘优化问题进行建模?
- angular - 如何初始化 Angular Material Datepicker 输入表单域?
- c++ - .cpp 文件中纯虚函数的正确返回值应该是多少?
- sql - 在 SQL 中按 DESC 和 ASC 排序
- python - 如何从python中的字典字典中获取列表列表?
- python - 如何在 python 中使用 twitter API 抓取包含特定链接的推文?
- lua - Lua 局部函数不选择局部变量成员,除非在声明时分配