在'/\[\.{2}([^\.].+?)\]/'
删除行并保存数据源时,我还想保存到持久存储。
我使用UITableView
保存我的自定义对象类型NSKeyedArchiver
的数组,但它立即失败:
2018-02-13 23:01:41.818945 + 0000 ProjectName [28680:5720571] - [_ SwiftValue encodeWithCoder:]:无法识别的选择器发送到实例0x60800004d290
2018-02-13 23:01:41.826553 + 0000 ProjectName [28680:5720571] ***由于未被捕获而终止应用 异常' NSInvalidArgumentException',原因:' - [_ SwiftValue encodeWithCoder:]:发送到实例的无法识别的选择器 0x60800004d290'
我到处搜索过,无法找到适用于我的任何内容。至于我可以告诉Participant
对象的数据类符合Participant
和NSObject
,并且已经实现了必要的方法。
编辑:非常感谢大家的反馈意见。代码如下,正如我之前所说的,如果我忽略了发布可能与我的经验相关的必要内容,那么感谢任何帮助!
数据类(摘录)
NSCoding
来自Private Func内部,我试图利用它并打破
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)
}
}
再次感谢您对我的帮助。
编辑2 :我已经完成了一些调试,我猜我对Xcode IDE和调试的经验不足阻碍了这一点,但它看起来是 let archivePath = Participant.ArchiveURL.path
let isSuccessfulSave = NSKeyedArchiver.archiveRootObject(participants, toFile: archivePath)
属性存储的对象抛出错误。这个属性是一个结构,我认为其他人倾向于作为一个问题。这是可解决的还是我需要查看另一种持久存储Structs的方法?
编辑3 :我已经解决了问题,但不知道如何将其标记为已解决。问题不是结构(我没有存储),而是 Enum 。使用ratePeriod
和NSKeyedArchiver
存储枚举时,您需要存储NSCoding
并将其重新组合为Int。即: -
编码
.rawValue
和
解码
aCoder.encode(ratePeriod.rawValue, forKey: PropertyKey.ratePeriod)
答案 0 :(得分:1)
您的自定义对象类型Participant需要是一个类(不是结构),特别是它必须是NSObject的子类。现在您可以成功采用NSCoding。
答案 1 :(得分:0)
关于如何使自定义类NSCoding
/ NSKeyedArchiver
合规,有一个非常simple article on NSHipster。我建议你看看。
作为基本答案,为了使您的对象与NSKeyedArchiver
一起使用,您需要告诉编码器/解码器如何编码/解码您的对象。例如,如果这是您的班级:
class Participant {
let name: String
let id: String
let age: Int
init(name: String, id: String, age: Int) {
self.name = name
self.id = id
self.age = age
}
}
您需要进行以下修改才能使其与NSKeyedArchiver一起使用。首先,声明您符合NSObject
和NSCoding
协议。然后实施encode
方法和convenience init?(coder:_)
初始化程序:
class Participant: NSObject, NSCoding {
let name: String
let id: String
let age: Int
init(name: String, id: String, age: Int) {
self.name = name
self.id = id
self.age = age
}
required convenience init?(coder aDecoder: NSCoder) {
guard let name = aDecoder.decodeObject(forKey: "name") as? String,
let id = aDecoder.decodeObject(forKey: "id") as? String,
let age = aDecoder.decodeObject(forKey: "age") as? Int else { return nil }
self.init(name: name, id: id, age: age)
}
func encode(with aCoder: NSCoder) {
aCoder.encode(self.name, forKey: "name")
aCoder.encode(self.id, forKey: "id")
aCoder.encode(self.age, forKey: "age")
}
}
答案 2 :(得分:-1)
尝试将@objc添加到swift等效的encodeWithCoder:方法中。同上解码init方法。我怀疑这是解决方案,但可能是。
另外,请说明如何在Swift中编写NSCoding方法。考虑到Swift和ObjC之间关于如何编写它们的内在转换,它们可能不匹配?
func encode(with aCoder: NSCoder) {