问题
A question from Implementing Codable for UIColor
struct WrapperOfNSCoding<Wrapped>: Codable where Wrapped: NSCoding {
var wrapped: Wrapped
init(_ wrapped: Wrapped) { self.wrapped = wrapped }
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
let data = try container.decode(Data.self)
guard let object = NSKeyedUnarchiver.unarchiveObject(with: data) else {
throw DecodingError.dataCorruptedError(in: container, debugDescription: "failed to unarchive an object")
}
guard let wrapped = object as? Wrapped else {
throw DecodingError.typeMismatch(Wrapped.self, DecodingError.Context(codingPath: container.codingPath, debugDescription: "unarchived object type was \(type(of: object))"))
}
self.wrapped = wrapped
}
func encode(to encoder: Encoder) throws {
let data = NSKeyedArchiver.archivedData(withRootObject: wrapped)
var container = try encoder.singleValueContainer()
try container.encode(data)
}
}
let colors = [NSColor.red, NSColor.brown]
print(colors)
let w = WrapperOfNSCoding(colors[0])
let jsonData = try! JSONEncoder().encode(w) - fails
let jsonData = try! JSONEncoder().encode(colors.map({ WrapperOfNSCoding($0) })) - succeeds
print(jsonData)
let colors2 = try! JSONDecoder().decode([WrapperOfNSCoding<NSColor>].self, from: jsonData).map({ $0.wrapped })
print(colors2)
The error is when a single value is used in the encoder
let w = WrapperOfNSCoding(colors[0])
let jsonData = try! JSONEncoder().encode(w)
error is
Fatal error: 'try!' expression unexpectedly raised an error: Swift.EncodingError.invalidValue(WrapperOfNSCoding #1...
This succeeds
let w = WrapperOfNSCoding([colors[0]])
let jsonData = try! JSONEncoder().encode(w)
Why would that be
回答1:
JSONEncoder need valid JSON context on the top level, which could be either [:] (Dictionary) or [] (Array), inside you can place an element like in this example string.
When you save any NSCoding object, the compiler treats that object as the string. In the case of JSONEncoder().encode(w), you are trying to encode an NSCoding object which acts as a string object instead of regular JSON object.
In the case of JSONEncoder().encode([w]), the object has created an array and each element has a string which is NSCoding in your case.
In another way w data is a string and [w] is an array with each index is having a string, therefore JSONEncoder is not giving you an error with [w] and giving you an error for w.
来源:https://stackoverflow.com/questions/49330725/wrapperofnscoding-fails-with-single-value