【发布时间】:2018-02-13 23:26:07
【问题描述】:
在UITableView 中删除一行并保存数据源时,我还想保存到持久存储中。
我正在使用NSKeyedArchiver 保存我的自定义对象类型Participant 的数组,但它立即失败:
2018-02-13 23:01:41.818945+0000 项目名称[28680:5720571] -[_SwiftValue encodeWithCoder:]:无法识别的选择器发送到实例 0x60800004d290
2018-02-13 23:01:41.826553+0000 ProjectName[28680:5720571] *** 由于未捕获而终止应用程序 异常'NSInvalidArgumentException',原因:'-[_SwiftValue encodeWithCoder:]: 无法识别的选择器发送到实例 0x60800004d290'
我到处搜索,找不到任何适合我的东西。据我所知,Participant 对象的数据类符合NSObject 和NSCoding 并实现了必要的方法。
编辑:感谢大家这么快的反馈。代码如下,正如我之前所说,如果我忽略了发布可能与我的经验相关的必要内容,那么我们将不胜感激地收到任何帮助!
数据类(摘录)
class Participant: NSObject, NSCoding {
//MARK: Properties
var name: String
var jobTitle: String?
var picture: UIImage?
var rate: Float
var ratePeriod: ratePeriods
//MARK: Archiving Paths
static let DocumentsDirectory = FileManager().urls(for: .documentDirectory, in: .userDomainMask).first!
static let ArchiveURL = DocumentsDirectory.appendingPathComponent("participants")
//MARK: Types
struct PropertyKey {
//THESE MUST NOT CHANGE ONCE BUILT
static let name = "name"
static let jobTitle = "jobTitle"
static let picture = "picture"
static let rate = "rate"
static let ratePeriod = "ratePeriod"
}
//MARK: Initialisation
init?(name: String, jobTitle: String?, picture: UIImage?, rate: Float?, ratePeriod: ratePeriods?) {
//The name must not be empty
guard !name.isEmpty else {
return nil
}
//Init stored properties
self.name = name
self.jobTitle = jobTitle ?? ""
self.picture = picture
self.rate = rate ?? 0.0
self.ratePeriod = ratePeriod ?? .annually
}
//MARK: NSCoding
func encode(with aCoder: NSCoder) {
aCoder.encode(name, forKey: PropertyKey.name)
aCoder.encode(jobTitle, forKey: PropertyKey.jobTitle)
aCoder.encode(picture, forKey: PropertyKey.picture)
aCoder.encode(rate, forKey: PropertyKey.rate)
aCoder.encode(ratePeriod, forKey: PropertyKey.ratePeriod)
}
required convenience init?(coder aDecoder: NSCoder) {
//The name is required. If we cannot decode a name string, the init should fail.
guard let name = aDecoder.decodeObject(forKey: PropertyKey.name) as? String else {
return nil
}
let jobTitle = aDecoder.decodeObject(forKey: PropertyKey.jobTitle) as? String
let picture = aDecoder.decodeObject(forKey: PropertyKey.picture) as? UIImage
let rate = aDecoder.decodeFloat(forKey: PropertyKey.rate)
let ratePeriod = aDecoder.decodeObject(forKey: PropertyKey.ratePeriod) as? ratePeriods
//Must call designated init
self.init(name: name, jobTitle: jobTitle, picture: picture, rate: rate, ratePeriod: ratePeriod)
}
}
从我试图使用它的 Private Func 内部,它中断了
let archivePath = Participant.ArchiveURL.path
let isSuccessfulSave = NSKeyedArchiver.archiveRootObject(participants, toFile: archivePath)
再次感谢您在这方面提供的任何帮助。
编辑 2:我做了更多的调试,我想我对 Xcode IDE 和调试的缺乏经验阻碍了这一点,但它看起来是被存储对象的 ratePeriod 属性那就是抛出错误。这个属性是一个结构,我认为其他人认为它是一个问题。这是可以解决的还是我需要寻找一种不同的方法来持久存储结构?
编辑 3:我已经解决了问题,但不知道如何将其标记为已解决。问题不在于 Struct(我没有存储它),而在于 Enum。当使用 NSKeyedArchiver 和 NSCoding 存储 Enums 时,您需要存储 .rawValue 并将其重构为 Int。即:-
编码
aCoder.encode(ratePeriod.rawValue, forKey: PropertyKey.ratePeriod)
和
解码
let ratePeriodIntValue = (aDecoder.decodeObject(forKey: PropertyKey.ratePeriod) as? Int) ?? ratePeriods.annually.rawValue
let ratePeriod = ratePeriods(rawValue: ratePeriodIntValue)
【问题讨论】:
-
你使用 Git 吗?如果可以,您可以分享链接以便我查看代码吗?
-
我冒昧地猜测您需要将对象转换为字典进行存储。但我需要查看您的代码才能确定发生了什么。
-
@Jake 如果回答问题所需的代码不在问题中,则需要在此处添加。移出网站意味着该帖子对其他人永远不会有用。
-
“据我所知,我的 Participant 对象的数据类符合 NSObject 和 NSCoding 并实现了必要的方法。”但是我们不相信你,编译器也不相信。
-
展示您的作品或准备结束您的主题。
标签: swift nskeyedarchiver