- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我需要从/向 JSON 格式的文件读取/写入 Codable(例如,Date)和 NSCoding(例如,NSMutableAttributedString)属性。在研究了如何使用 Codable 读取和写入文件、如何以 JSON 格式执行此操作以及当某些属性不符合 Codable(但确实符合 NSCoding)时如何将 NSCoding 与 Codable 结合之后,我拼凑在一起以下代码并在此过程中使自己感到困惑。
我终于想出了如何测试它,并相应地进行了更改。但我仍然想知道这三种解码器/编码器类型(NSCoding、Codable 和 JSON)如何相互作用或相互替代。
import Foundation
class Content: Codable {
// Content
var attrStr = NSMutableAttributedString(string: "")
var date: Date?
// Initializer for content
init(attrStr: NSMutableAttributedString, date: Date) {
self.attrStr = attrStr
self.date = date
}
// Need to explicitly define because NSMutableAttributedString isn't codable
enum CodingKeys: String, CodingKey {
case attrStr
case date
}
// Need to explicitly define the decoder. . . .
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
date = try container.decode(Date.self, forKey: .date)
let attrStrData = try container.decode(Data.self, forKey: .attrStr)
attrStr = NSKeyedUnarchiver.unarchiveObject(with: attrStrData) as? NSMutableAttributedString ?? NSMutableAttributedString(string: "Error!")
}
// Need to explicitly define the encoder. . . .
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(date, forKey: .date)
let attrStrData = NSKeyedArchiver.archivedData(withRootObject: attrStr)
try container.encode(attrStrData, forKey: .attrStr)
}
static func getFileURL() -> URL {
// Get the directory for the file
let docsDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
// Get the full path and filename
return docsDir.appendingPathComponent("contentArray").appendingPathExtension("cntnt")
}
static func saveToFile(content: [Content]) {
// Get the file's URL
let fileURL = getFileURL()
do {
// Encode the data
let data = try JSONEncoder().encode(content)
// Write to a/the file
try data.write(to: fileURL)
} catch {
print("Could not encode or save to the file!")
}
}
static func loadFromFile() -> [Content] {
// Get the file's URL
let fileURL = getFileURL()
do {
// Read from the file
let data = try Data(contentsOf: fileURL)
// Decode the data
return try JSONDecoder().decode([Content].self, from: data)
} catch {
print("Could not decode or read from the file!")
return []
}
}
}
最佳答案
About your alternative, I wouldn't know how to do that.
我尝试为 NSMutableAttributedString
实现 Codable
。我不得不嵌入而不是子类化它,因为它是一个类簇。 Source
class MutableAttributedStringContainer: Codable {
let attributedString: NSMutableAttributedString
init(attributedString: NSMutableAttributedString) {
self.attributedString = attributedString
}
public required init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
let data = try container.decode(Data.self)
let archiver = try NSKeyedUnarchiver(forReadingFrom: data)
attributedString = NSMutableAttributedString(coder: archiver)!
}
public func encode(to encoder: Encoder) throws {
let archiver = NSKeyedArchiver(requiringSecureCoding: true)
attributedString.encode(with: archiver)
var container = encoder.singleValueContainer()
try container.encode(archiver.encodedData)
}
}
这是一个如何使用它的例子。
func testing() {
let attributedString = NSMutableAttributedString(string: "Hello world!")
let attributedStringContainer = MutableAttributedStringContainer(attributedString: attributedString)
// Necessary because encoding into a singleValueContainer() creates a
// JSON fragment instead of a JSON dictionary that `JSONEncoder` wants
// create.
struct Welcome: Codable {
var attributedString: MutableAttributedStringContainer
}
let welcome = Welcome(attributedString: attributedStringContainer)
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
let data = try! encoder.encode(welcome)
print(String(bytes: data, encoding: .utf8) as Any)
let decoder = JSONDecoder()
let welcome2 = try! decoder.decode(Welcome.self, from: data)
print("decoded to string:", welcome2.attributedString.attributedString.string)
}
But it also looks wrong. For example, the explicitly defined decoder and encoder seem disconnected from the JSONDecoder and -Encoder.
Codable
结构相互构建。如果所有底层结构都实现了Codable
,编译器就可以自己创建编码和解码函数。如果没有,开发人员必须对它们进行编码并将它们放在 CodingKey
上,解码时也是如此。
例如,可以以任何方式将它们转换为数据,然后将它们作为数据编码到 CodingKey
。也许读一个Raywenderlich Tutorial在 Codable
上更好地理解它。
There should be a discernible processing stream, but I can't see how the three kinds of decoders/encoders interact or substitute for one another.
有支持特定编码器/解码器对的解码器/编码器和方法。
NSCoding
与 NSKeyedUnarchiver/NSKeyedArchiver
一起工作并返回 NSData
这只是数据,虽然不是人类可读的形式。
Codable
与任何支持 Codable
的编码器/解码器对一起工作,更具体地说,在我们的例子中是 JSONEncoder/JSONDecoder
,它返回 Data
是人类可读的格式JSON
,可以打印,因为这里的数据是用.utf8
编码的。
关于json - NSCoding 和 Codable 属性 <=> JSON 格式 <=>(读/写)文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51911518/
假设我有这个 Swift 类: class Foo: NSObject, NSCoding { var stringMember: String var intMember: Int
我需要对包含多个自定义 NSObject 实例的数组进行编码类(class)。但是,这样做时,它会返回带有消息的崩溃: -[Person encodeWithCoder:]: unrecognized
import Foundation class C: NSObject, NSCoding { var n: String = "" override init() {
我正在尝试将 NSCoding 协议(protocol)添加到我的自定义类中: class Convo: NSObject, NSCoding { var name: String v
我有一个 costum 对象,它引用了另一个自定义对象。如何在我的 - (void)encodeWithCoder:(NSCoder *)encoder 方法中对一个自定义对象内的自定义对象进行编码?
我有 .h 和 .m 来实现 NSCoding,但是 mutableArray 对象计数总是 0 ... .h #import @interface Favorite : NSObject {
我有一个自定义对象,我想将其保存到磁盘而不是内存。自定义对象有子对象,子对象有子对象等等。这棵树相当广泛。其中一个子对象有 30 多个属性,其中 6 个是子对象本身。 如果我想使用NSCoding,是
我有两个类:Contact 和 Bill。 Contact 有一个类型为 Bill 的数组。 当我坚持使用 NSKeyedArchiver 时,我的联系人保持得很好,但是,它不会保持 Bill 数组。
我有一个带有 NSString 键和 Class (objc_class) 值的 NSDictionary,我想使用 NSCoding 存档这个字典 协议(protocol)。 我如何存档“类”对象?
当使用 NSCoding 或 NSKeyedArchiver 建立父子关系时;我无法在子项中设置对父项的引用,因为它最终会在 Swift Playground 上崩溃。 我想在我的 Child 类中引
我一辈子都弄不明白为什么我会收到此类不符合 NSCoding 协议(protocol)的错误。也许另一双眼睛会有所帮助。我试图添加注释以明确每个函数在做什么。 import Foundation im
我使我的以下 Person 类符合 NSCoding 协议(protocol)。 class Person: NSObject, NSCoding{ var age:Int var h
我正在尝试能够序列化和解码自定义类。该类本身有一个属性,它是一个枚举数组,如下所示: (我已经阅读了如何使用原始值并将其序列化,但我还没有弄清楚如何使用这样的数组来做到这一点)。 enum WeekD
我有一个带有 String 属性和 NSImage 属性的“Thing”对象; Thing 类有 encodeWithCoder: 和 decodeWithCoder: 方法,我可以使用 NSKeye
我正在使用 NSCoding 来存档/取消存档自定义类作为数据持久化的方法。如果对象是 NSObject 的子类,它工作正常,但我也有对象是自定义对象的子类。我是否需要更改 initWithCoder
我有一系列嵌套对象需要通过 NSCoding 协议(protocol)进行处理,以便我可以将顶级对象保存到 NSUserDefaults 中。 这是对象的结构: '讲师'类 NSMutableArra
-(void)transformObjects:(NSMutableArray*)array key:(NSString*)key { NSMutableArray* archiveArray
我在 Swift 中使用 NSCoding 时遇到问题。我试图实现该协议(protocol),但每当我调用我的 save() 方法时都会发生崩溃。 Xcode 在 encodeWithCoder 中将
我正在尝试使用基本的父子对象继承系统编写一个简单的 RPG,该系统被保存并加载到游戏状态中,但是当发生加载时,父级没有数据出现,我正在努力理解为什么。 为了简单起见,我做了一个简单的父子对象继承,其中
我有一个 NSPopUpButtonCell 的自定义子类,以便我可以覆盖其 drawBezelWithFrame:inView: 方法。 目前,我必须使用 initTextCell:pullsDow
我是一名优秀的程序员,十分优秀!