无法使用类型为'NSAttributedString'的参数列表调用'encode'

时间:2019-01-10 01:15:01

标签: swift nsattributedstring nskeyedarchiver

如何编码NSAttributedString并使用UserDefaults将其存储在磁盘中?

首先,我尝试设置Codable协议:

class CoachProgram: Codable {
    var name: String
    var details: NSAttributedString
}

,但是编译器产生Type 'Coach' does not conform to protocol 'Encodable'。因此,我开始实现encode(to:)方法:

public func encode(to encoder: Encoder) throws {
    var container = encoder.unkeyedContainer()
    try container.encode(details)
                  ^~~~~~ "error: cannot invoke 'encode' with an argument list of type '(NSAttributedString)'"
}

但没有成功。

我的想法是像这样使用CoachProgram

let archiver = NSKeyedArchiver()
do {
    try archiver.encodeEncodable(coachProgram, forKey: NSKeyedArchiveRootObjectKey)
}
catch {
    print(error)
}
UserDefaults.standard.set(archiver.encodedData, forKey: "CoachProgram")

1 个答案:

答案 0 :(得分:1)

第一个问题:我试图使用无密钥容器,这没有任何意义,因为我肯定需要一个密钥容器,因为我有2个属性( name < / strong>和 details )。

因此,我需要实现一些CodingKey并使用decoder.container(keyedBy:)方法。

第二个问题:经过一些实验,我注意到我可以通过简单地使用NSKeyedArchiverNSAttributedString变成DataDataCodable,因此我可以对其进行编码和解码。

所以,我得到的最终解决方案是:

class CoachProgram: Codable {
    var name: String
    var details: NSAttributedString

    enum CodingKeys: String, CodingKey {
        case name
        case details
    }

    init(name: String, details: NSAttributedString) {
        self.name = name
        self.details = details
    }

    required public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        if let name = try container.decodeIfPresent(String.self, forKey: .name) {
            self.name = name
        }
        if let data = try container.decodeIfPresent(Data.self, forKey: .details) {
            self.details = NSKeyedUnarchiver.unarchiveObject(with: data) as? NSAttributedString ?? NSAttributedString()
        }
    }

    public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(name, forKey: .name)
        try container.encode(NSKeyedArchiver.archivedData(withRootObject: details), forKey: .details)
    }
}

实际情况:

let coachProgram = CoachProgram(name: "John Doe", details: NSAttributedString())

let archiver = NSKeyedArchiver()
do {
    try archiver.encodeEncodable(coachProgram, forKey: NSKeyedArchiveRootObjectKey)
}
catch {
    print(error)
}
UserDefaults.standard.set(archiver.encodedData, forKey: "CoachProgram")