自定义结构:类型不符合协议 'Decodable'
Custom Struct: Type does not conform to protocol 'Decodable'
我希望能够将 Custom-struct
保存到 UserDefaults
但为此我需要它是 Codable
.. 我试过这样:
struct Wishlist: Codable {
var name: String
var image: UIImage
var wishData: [Wish]
var color: UIColor
var textColor: UIColor
var index: Int
}
但这给了我这个 error
:
Type 'Wishlist' does not conform to protocol 'Decodable'
这是我的 Class Wish
,也许这就是问题所在:
class Wish: NSObject {
public var wishName : String?
public var checkedStatus : Bool?
public var wishLink : String?
public var wishPrice : String?
public var wishNote : String?
public var wishImage : UIImage?
init(withWishName name: String, link: String, price: String, note: String, image: UIImage, checked: Bool) {
super.init()
wishName = name
checkedStatus = checked
wishLink = link
wishPrice = price
wishNote = note
wishImage = image
}
}
我哪里做错了??
UIImage
不符合Codable
。您可以先将其转换为 Base64,然后将 that 存储在 UserDefaults
.
中
您需要让 Wish
采用 Codable
。
但是因为 UIImage
和 UIColor
不是 Codable
,您必须按照 Encoding and Decoding Custom Types:
中的概述手动实施它们
struct Wishlist: Codable {
var name: String
var image: UIImage
var wishes: [Wish]
var color: UIColor
var textColor: UIColor
var index: Int
enum CodingKeys: String, CodingKey {
case name, image, wishData, color, textColor, index
}
init(name: String, image: UIImage, wishes: [Wish], color: UIColor, textColor: UIColor, index: Int) {
self.name = name
self.image = image
self.wishes = wishes
self.color = color
self.textColor = textColor
self.index = index
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
name = try values.decode(String.self, forKey: .name)
wishes = try values.decode([Wish].self, forKey: .wishData)
color = try values.decode(Color.self, forKey: .color).uiColor
textColor = try values.decode(Color.self, forKey: .textColor).uiColor
index = try values.decode(Int.self, forKey: .index)
let data = try values.decode(Data.self, forKey: .image)
guard let image = UIImage(data: data) else {
throw DecodingError.dataCorruptedError(forKey: .image, in: values, debugDescription: "Invalid image data")
}
self.image = image
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(name, forKey: .name)
try container.encode(wishes, forKey: .wishData)
try container.encode(Color(uiColor: color), forKey: .color)
try container.encode(Color(uiColor: textColor), forKey: .textColor)
try container.encode(index, forKey: .index)
try container.encode(image.pngData(), forKey: .image)
}
}
struct Wish: Codable {
public var name: String
public var checkedStatus: Bool
public var link: String
public var price: String
public var note: String
public var image: UIImage
init(name: String, link: String, price: String, note: String, image: UIImage, checkedStatus: Bool) {
self.name = name
self.checkedStatus = checkedStatus
self.link = link
self.price = price
self.note = note
self.image = image
}
enum CodingKeys: String, CodingKey {
case name, checkedStatus, link, price, note, image
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
name = try values.decode(String.self, forKey: .name)
checkedStatus = try values.decode(Bool.self, forKey: .checkedStatus)
link = try values.decode(String.self, forKey: .link)
price = try values.decode(String.self, forKey: .price)
note = try values.decode(String.self, forKey: .note)
let data = try values.decode(Data.self, forKey: .image)
guard let image = UIImage(data: data) else {
throw DecodingError.dataCorruptedError(forKey: .image, in: values, debugDescription: "Invalid image data")
}
self.image = image
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(name, forKey: .name)
try container.encode(checkedStatus, forKey: .checkedStatus)
try container.encode(link, forKey: .link)
try container.encode(price, forKey: .price)
try container.encode(note, forKey: .note)
try container.encode(image.pngData(), forKey: .image)
}
}
我将使用它作为编码 UIColor
对象的便捷方式:
struct Color: Codable {
let red: CGFloat
let green: CGFloat
let blue: CGFloat
let alpha: CGFloat
init(red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) {
self.red = red
self.green = green
self.blue = blue
self.alpha = alpha
}
init(uiColor: UIColor) {
var red: CGFloat = 0
var green: CGFloat = 0
var blue: CGFloat = 0
var alpha: CGFloat = 0
uiColor.getRed(&red, green: &green, blue: &blue, alpha: &alpha)
self.red = red
self.green = green
self.blue = blue
self.alpha = alpha
}
var uiColor: UIColor { UIColor(red: red, green: green, blue: blue, alpha: alpha) }
}
请注意,我做了一些不相关的更改:
这两个都是我做的struct
。除非必要,否则我不会引入引用类型(更不用说 NSObject
子类了)。
我简化了一些 属性 名称。例如。在 Wish
中,我们通常不会在 属性 名称中使用 wish
前缀。我也不会在 属性 名称中使用“数据”,除非它实际上是 Data
.
我更新了 init
方法以使用标准命名约定。
在您的情况下,您应该添加 CodingKeys
枚举而不是使用 UIColor
或 UIImage
数据类型。我之前遇到了同样的错误,但后来我意识到 CodingKey 与结构不匹配,也没有 non-codable
数据类型。只需将数据类型更改为您的自定义可编码对象。
错误的例子:
public struct DtClip: Codable {
// MARK: Properties
public var video: String?
public var preview: String?
public var clip: String?
public var trailer: Any?
enum CodingKeys: String, CodingKey {
case video = "video"
case preview = "preview"
case clip = "clip"
}
}
从示例中我们知道 trailer
还不在 codingKeys
中。您应该将所有道具添加到 CodingKeys
。并且 Any
数据类型应更改为可编码数据类型,如 String
、Int
或 Trailer
(自定义可编码数据类型)。下面是正确的例子:
public struct DtClip: Codable {
// MARK: Properties
public var video: String?
public var preview: String?
public var clip: String?
public var trailer: Trailer?
enum CodingKeys: String, CodingKey {
case video = "video"
case preview = "preview"
case clip = "clip"
case trailer = "trailer"
}
}
public struct Trailer: Codable {
// MARK: Properties
public var name: String?
public var id: Int?
enum CodingKeys: String, CodingKey {
case name, url
}
}
我希望能够将 Custom-struct
保存到 UserDefaults
但为此我需要它是 Codable
.. 我试过这样:
struct Wishlist: Codable {
var name: String
var image: UIImage
var wishData: [Wish]
var color: UIColor
var textColor: UIColor
var index: Int
}
但这给了我这个 error
:
Type 'Wishlist' does not conform to protocol 'Decodable'
这是我的 Class Wish
,也许这就是问题所在:
class Wish: NSObject {
public var wishName : String?
public var checkedStatus : Bool?
public var wishLink : String?
public var wishPrice : String?
public var wishNote : String?
public var wishImage : UIImage?
init(withWishName name: String, link: String, price: String, note: String, image: UIImage, checked: Bool) {
super.init()
wishName = name
checkedStatus = checked
wishLink = link
wishPrice = price
wishNote = note
wishImage = image
}
}
我哪里做错了??
UIImage
不符合Codable
。您可以先将其转换为 Base64,然后将 that 存储在 UserDefaults
.
您需要让 Wish
采用 Codable
。
但是因为 UIImage
和 UIColor
不是 Codable
,您必须按照 Encoding and Decoding Custom Types:
struct Wishlist: Codable {
var name: String
var image: UIImage
var wishes: [Wish]
var color: UIColor
var textColor: UIColor
var index: Int
enum CodingKeys: String, CodingKey {
case name, image, wishData, color, textColor, index
}
init(name: String, image: UIImage, wishes: [Wish], color: UIColor, textColor: UIColor, index: Int) {
self.name = name
self.image = image
self.wishes = wishes
self.color = color
self.textColor = textColor
self.index = index
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
name = try values.decode(String.self, forKey: .name)
wishes = try values.decode([Wish].self, forKey: .wishData)
color = try values.decode(Color.self, forKey: .color).uiColor
textColor = try values.decode(Color.self, forKey: .textColor).uiColor
index = try values.decode(Int.self, forKey: .index)
let data = try values.decode(Data.self, forKey: .image)
guard let image = UIImage(data: data) else {
throw DecodingError.dataCorruptedError(forKey: .image, in: values, debugDescription: "Invalid image data")
}
self.image = image
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(name, forKey: .name)
try container.encode(wishes, forKey: .wishData)
try container.encode(Color(uiColor: color), forKey: .color)
try container.encode(Color(uiColor: textColor), forKey: .textColor)
try container.encode(index, forKey: .index)
try container.encode(image.pngData(), forKey: .image)
}
}
struct Wish: Codable {
public var name: String
public var checkedStatus: Bool
public var link: String
public var price: String
public var note: String
public var image: UIImage
init(name: String, link: String, price: String, note: String, image: UIImage, checkedStatus: Bool) {
self.name = name
self.checkedStatus = checkedStatus
self.link = link
self.price = price
self.note = note
self.image = image
}
enum CodingKeys: String, CodingKey {
case name, checkedStatus, link, price, note, image
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
name = try values.decode(String.self, forKey: .name)
checkedStatus = try values.decode(Bool.self, forKey: .checkedStatus)
link = try values.decode(String.self, forKey: .link)
price = try values.decode(String.self, forKey: .price)
note = try values.decode(String.self, forKey: .note)
let data = try values.decode(Data.self, forKey: .image)
guard let image = UIImage(data: data) else {
throw DecodingError.dataCorruptedError(forKey: .image, in: values, debugDescription: "Invalid image data")
}
self.image = image
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(name, forKey: .name)
try container.encode(checkedStatus, forKey: .checkedStatus)
try container.encode(link, forKey: .link)
try container.encode(price, forKey: .price)
try container.encode(note, forKey: .note)
try container.encode(image.pngData(), forKey: .image)
}
}
我将使用它作为编码 UIColor
对象的便捷方式:
struct Color: Codable {
let red: CGFloat
let green: CGFloat
let blue: CGFloat
let alpha: CGFloat
init(red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) {
self.red = red
self.green = green
self.blue = blue
self.alpha = alpha
}
init(uiColor: UIColor) {
var red: CGFloat = 0
var green: CGFloat = 0
var blue: CGFloat = 0
var alpha: CGFloat = 0
uiColor.getRed(&red, green: &green, blue: &blue, alpha: &alpha)
self.red = red
self.green = green
self.blue = blue
self.alpha = alpha
}
var uiColor: UIColor { UIColor(red: red, green: green, blue: blue, alpha: alpha) }
}
请注意,我做了一些不相关的更改:
这两个都是我做的
struct
。除非必要,否则我不会引入引用类型(更不用说NSObject
子类了)。我简化了一些 属性 名称。例如。在
Wish
中,我们通常不会在 属性 名称中使用wish
前缀。我也不会在 属性 名称中使用“数据”,除非它实际上是Data
.我更新了
init
方法以使用标准命名约定。
在您的情况下,您应该添加 CodingKeys
枚举而不是使用 UIColor
或 UIImage
数据类型。我之前遇到了同样的错误,但后来我意识到 CodingKey 与结构不匹配,也没有 non-codable
数据类型。只需将数据类型更改为您的自定义可编码对象。
错误的例子:
public struct DtClip: Codable {
// MARK: Properties
public var video: String?
public var preview: String?
public var clip: String?
public var trailer: Any?
enum CodingKeys: String, CodingKey {
case video = "video"
case preview = "preview"
case clip = "clip"
}
}
从示例中我们知道 trailer
还不在 codingKeys
中。您应该将所有道具添加到 CodingKeys
。并且 Any
数据类型应更改为可编码数据类型,如 String
、Int
或 Trailer
(自定义可编码数据类型)。下面是正确的例子:
public struct DtClip: Codable {
// MARK: Properties
public var video: String?
public var preview: String?
public var clip: String?
public var trailer: Trailer?
enum CodingKeys: String, CodingKey {
case video = "video"
case preview = "preview"
case clip = "clip"
case trailer = "trailer"
}
}
public struct Trailer: Codable {
// MARK: Properties
public var name: String?
public var id: Int?
enum CodingKeys: String, CodingKey {
case name, url
}
}