Fatal error: DictionaryString, Any does not conform to Decodable because Any does not conform to Decodable
Maybe you are misunderstanding how Codable
works. It's based on concrete types. Any
is not supported.
In your case you might create a struct like
struct Something: Decodable {
let success : Bool
let lastId : Int?
let hasMore: Bool
let foundEndpoint: URL
let error: String?
}
And decode the JSON
func loadLocalJSON() {
let url = Bundle.main.url(forResource: "localJSON", withExtension: "json")!
let data = try! Data(contentsOf: url)
let colors = try! JSONDecoder().decode(Something.self, from: data)
print(colors)
}
Any crash will reveal a design error. The sense of using null
in a file in the main bundle is another question.
Dictionary of String:Any does not conform to protocol 'Decodable'
You cannot currently decode a [String: Any]
with the Swift coding framework. You'll need to drop to a lower-level deserialization strategy and decode “by hand” if you need to decode a [String: Any]
. For example, if your input is JSON, you can use Foundation's JSONSerialization
or a third-party library like SwiftyJSON.
There has been discussion of this issue on Swift Evolution: “Decode a JSON object of unknown format into a Dictionary with Decodable in Swift 4”. Apple's main Coding/Codable programmer, Itai Ferber, has been involved in the discussion and is interested in providing a solution, but it is unlikely to happen for Swift 5 (which will probably be announced at WWDC 2018 and finalized around September/October 2018).
You could copy the implementation of JSONDecoder
(it's open source) into your project and modify it to add the ability to get an unevaluated [String: Any]
. Itai discusses the required modifications in the thread I linked above.
Codable class doesn't conform to protocol 'Decodable'
It is not necessary to separate the structs. The error occurs because you have added too many keys in the CodingKeys
enum. If you keep only the required ones, then it will work:
struct Model: Codable {
let aps: Aps
let link: String?
let checkAction: String?
enum CodingKeys: String, CodingKey {
case aps ,link
case checkAction = "gcm.notificaiton.check_action"
}
struct Aps: Codable {
let alert: Alert
let sound: String?
struct Alert: Codable {
let title: String?
let body: String?
}
}
}
alert
, sound
etc are not coding keys of Model
. They are coding keys of Aps
. It is not necessary to specify them in Aps
, because they are the same as the property names.
Custom Struct: Type does not conform to protocol 'Decodable'
You will need to make Wish
adopt Codable
.
But because UIImage
and UIColor
are not Codable
, you’ll have to manually implement them as outlined in 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)
}
}
Where I’d use this as a convenient way to encode UIColor
objects:
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) }
}
Note, I did a couple of unrelated changes:
I made both of these
struct
. I wouldn’t introduce reference types (much lessNSObject
subclasses) unless necessary.I simplified some of the property names. E.g. in
Wish
, we wouldn’t generally usewish
prefix in property names. I also wouldn’t use “data” in a property name unless it was, in fact, aData
.I updated
init
methods to use standard naming conventions.
Codable class does not conform to protocol Decodable
Why am I getting a "Type 'Bookmark' does not conform to protocol 'Decodable'" error message
It's either because Publication isn't Decodable (you have not shown what it is, so it's hard to tell) or because of the weak
designation on publication
.
Either way, it's easy to fix: you just need to implement init(from:)
to complete the implementation of Decodable; the compiler is simply telling you that this implementation cannot be synthesized.
My structure does not conform to protocol 'Decodable' / 'Encodable' if I use protocol type in my structure in swift
JSONDecoder
needs to know the concrete type of thing that you want to decode the JSON into. After all, everything must have a concrete type at runtime, that you can get with type(of:)
. You can't tell it to just "decode a protocol". The encoder is a bit different though - it doesn't actually need to know the concrete type, and there is a way to get around it.
It seems like the type of UIConfig
depends on objectid
, so we can check objectid
and decide what type of UIConfig
to decode:
enum CodingKeys: CodingKey {
case id, objectid, config
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(String.self, forKey: .id)
objectid = try container.decode(String.self, forKey: .objectid)
if objectid == "bd_label" {
config = try container.decode(LabelConfig.self, forKey: .config)
} else if objectid == "bd_button" {
config = try container.decode(ButtonConfig.self, forKey: .config)
}
// other cases...
else {
throw DecodingError.dataCorruptedError(forKey: .config, in: container, debugDescription: "no suitable config type found for objectid \(objectid)!")
}
}
For the Encodable
part, you can make a "type eraser"-like thingy:
struct AnyEncodable: Encodable {
let encodeFunction: (Encoder) throws -> Void
init(_ encodable: Encodable) {
encodeFunction = encodable.encode(to:)
}
func encode(to encoder: Encoder) throws {
try encodeFunction(encoder)
}
}
and do:
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encode(objectid, forKey: .objectid)
try container.encode(AnyEncodable(config), forKey: .config)
}
By using AnyEncodable
, we are basically wrapping the protocol in a concrete type, but don't worry - this won't actually create an extra pair of curly brackets in the JSON.
Swift Codable: Cannot decode dictionary of type [String: Any] or [String: Decodable]
What you are looking for is nestedContainer
. It helps you "skip" a hierarchy level in your JSON. Ie: let's imagine that in your code, it's all in the same level (one struct), but in the JSON, it's not, there is a sub dictionary.
For test purpose, your JSON might look like:
{
"title": "normal",
"tracks": {
"name": "myName",
"total": 3
}
}
If we want in our model:
struct TestStruct: Codable {
let title: String
let name: String
let total: Int
}
We need to use nestedContainer(keyedBy: forKey:)
:
extension TestStruct {
enum TopLevelKeys: String, CodingKey {
case title
case tracks
}
enum NestedLevelCodingKeys: String, CodingKey {
case name
case total
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: TopLevelKeys.self)
self.title = try container.decode(String.self, forKey: .title)
let subcontainer = try container.nestedContainer(keyedBy: NestedLevelCodingKeys.self, forKey: TopLevelKeys.tracks)
self.name = try subcontainer.decode(String.self, forKey: .name)
self.total = try subcontainer.decode(Int.self, forKey: .total) //You can use here a `decodeIfPresent()` if needed, use default values, etc.
}
}
In your sample, you used decodeIfPresent()
for the subdictionary. It's unclear if it was for test purpose, or if the sub dictionary was sometimes not present.
If that's the case and you can have a JSON like this:
{
"title": "normal"
}
Then, before calling nestedContainer(keyedBy: forKey:)
, use if container.contains(TopLevelKeys.tracks) {}
and set default values if needed in the else
case.
SwiftUI - Type 'Service' does not conform to protocol 'Decodable'
Codable
can't have Any
, plus businessLocation
is a dictionary not an array, so Replace
var businessLocation: Array<Any>
with
var businessLocation:[String:String]
OR
Models
// MARK: - Element
struct Root: Codable {
let id, name: String
let items: [Item]
}
// MARK: - Item
struct Service: Codable {
let id: Int
let businessName, businessTelephone, businessEmail, businessWebsite: String
let businessLocation: BusinessLocation
let travelLimit: Int
let itemDescription: String
let categories: [String]
enum CodingKeys: String, CodingKey {
case id, businessName, businessTelephone, businessEmail, businessWebsite, businessLocation, travelLimit
case itemDescription = "description"
case categories
}
}
// MARK: - BusinessLocation
struct BusinessLocation: Codable {
let latitude, longitude: String
}
Decode
do {
let res = try JSONDecoder().decode([Root].self, from: data)
print(res)
}
catch {
print(error)
}
Related Topics
How to Insert a Sublayer in Swift
How to Restrict an Enum to Certain Cases of Another Enum
Core Image Filter Cisourceovercompositing Not Appearing as Expected with Alpha Overlay
How to Split a String into a [String] and Not [Substring]
Unwrapping Optional in Swiftui View
How to Get Mouse Location with Swiftui
How to Define Static Constant in a Generic Class in Swift
How to Unwrap Arbitrarily Deeply Nested Optionals in Swift
Toolbar Is Deleting My Back Button in the Navigationview
Ambigious Reference to Member Request() Issues with Alamofire After Migration to Swift 3
How to Convert 4 Bytes to a Swift Float
Explit Conformance to Codable Removes Memberwise Initializer Generation on Structs
No More 'Private Init' in Swift
Repeating Action Continuously in Swiftui
iOS 13.1 Cannot Save File to App Directory
Calling Stop() on Avaudioplayernode After Finished Playing Causes Crash