无法使用 'NSAttributedString' 类型的参数列表调用 'encode'
Cannot invoke 'encode' with an argument list of type 'NSAttributedString'
如何编码 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")
第一个问题:我试图使用一个未加密的容器,但这没有意义,因为我确实需要一个加密的容器,因为我有 2 个属性(name
和 details
).
所以,我需要实现一些 CodingKey
并使用 decoder.container(keyedBy:)
方法。
第二个问题: 经过一些实验,我注意到我可以通过简单地使用 NSKeyedArchiver
将 NSAttributedString
变成 Data
! Data
是 Codable
所以我可以对其进行编码和解码。
所以,我得到的最终解决方案是:
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")
如何编码 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")
第一个问题:我试图使用一个未加密的容器,但这没有意义,因为我确实需要一个加密的容器,因为我有 2 个属性(name
和 details
).
所以,我需要实现一些 CodingKey
并使用 decoder.container(keyedBy:)
方法。
第二个问题: 经过一些实验,我注意到我可以通过简单地使用 NSKeyedArchiver
将 NSAttributedString
变成 Data
! Data
是 Codable
所以我可以对其进行编码和解码。
所以,我得到的最终解决方案是:
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")