问题
Is it possible to implement the Encodable
and Decodable
properties for UIColor
When I try to add a Decodable
extension I get an error
extension UIColor : Decodable {
public required init(from decoder: Decoder) throws {
self.init(red: 1, green: 1, blue: 1, alpha: 1)
}
}
error: ColorStuff.playground:98:21: error: initializer requirement 'init(from:)' can only be satisfied by a
required
initializer in the definition of non-final class 'UIColor' public required init(from decoder: Decoder) throws {
Am I missing something obvious here?
I have no issues with the Encodable
extension - it seems its a Decodable
issue.
The error message implies to me that I cannot do this due to not having access to the UIColor
class definition
回答1:
You cannot make UIColor
conform to Decodable
in an extension because of the error given by the compiler.
One solution is to make a Codable
wrapper type and use that instead.
Since UIColor
already conforms to NSCoding
, let's just write a generic type so we can encode and decode anything that conforms to NSCoding
.
import UIKit
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 = [UIColor.red, UIColor.brown]
print(colors)
let jsonData = try! JSONEncoder().encode(colors.map({ WrapperOfNSCoding($0) }))
let colors2 = try! JSONDecoder().decode([WrapperOfNSCoding<UIColor>].self, from: jsonData).map({ $0.wrapped })
print(colors2)
来源:https://stackoverflow.com/questions/48566443/implementing-codable-for-uicolor