A codable structure contains a protocol property
You cannot do that because a protocol only states what you must do. So when you conform your protocol X
to Codable
, it only means that any type that conforms to X
must also conform to Codable
but it won't provide the required implementation. You probably got confused because Codable
does not require you to implement anything when all your types already are Codable
. If Codable
asked you to, say, implement a function called myFunction
, your OrderItem
would then lack the implementation of that function and the compiler would make you add it.
Here is what you can do instead:
struct Order<T: OrderItem>: Codable {
var id:String
var sn:String = ""
var items: [T] = []
var createdAt:Int64 = 0
var updatedAt:Int64 = 0
}
You now say that items
is a generic type that conforms to OrderItem
.
Decoding/Encoding a struct with protocol type properties
It's a limitation of Swift that a protocol cannot conform to itself. Thus from
and to
do not conform to Codable
as bizarre as that seems.
You can get around it by using generics which basically means you declare from
and to
as arbitrary types that conform to Codable
. Here's how:
struct Configuration<F: Connection, T: Connection>: Codable {
var from: F
var to: T
}
let myFrom = SFTPConnection(path: "foo", user: "me", sshKey: "hgfnjsfdjs")
let myTo = FTPConnection(path: "foo", user: "me", password: "hgfnjsfdjs")
let example = Configuration(from: myFrom, to: myTo)
So F
and T
are types that conform to Connection
. When you instantiate example
in the last line, the compiler infers F
is SFTPConnection
and T
is FTPConnection
.
Once I added the generic parameters, Configuration
was able to synthesise the conformance to Codable
without the extension.
To answer Sh_kahn's point about having two generic parameters, I did this to allow from
and to
to be connections of different types. If you always want the two connections to be of the same type i.e. always two SFTPConnection
s or two FTPConnection
s you should declare the Configuration
like this:
struct Configuration<C: Connection>: Codable {
var from: C
var to: C
}
Codable variable inside Codable struct causes error
The problem for the compiler here is that normally when a type is defined to conform to Codable
then the compiler synthesises code for you to make Person
in this case conform to the protocol. It does this by creating an implementation of init(from decoder: Decoder) throws
and one of func encode(to encoder: Encoder) throws
for you.
But when you change selectedItem
to be of type Codable
then the compiler can no longer synthesise these methods since it needs to know exactly what properties the type of selectedItem
has to correctly generate the code.
What you need to do here is to use generics
struct Person<T: Codable>: Codable {
var name: String
var age: Double
var birthday: Date
var selectedItem: T
}
struct Car: Codable {
var companyName: String
var creationDate: Date
}
struct iPhone: Codable {
var model: String
var creationDate: Date
var isScreenBroken: Bool = true
}
Then the compiler is happy again and you can use it like
let person = Person(name: "Joe", age: 40, birthday: date, selectedItem: Car(companyName: "Ford", creationDate: Date()))
My structure does not conform to protocol 'Decodable' / 'Encodable'
In order for a class or a struct to conform to a protocol, all properties of that class or struct must conform to the same protocol.
UIImage
does not conform to Codable
, so any class or struct that has properties of type UIImage
won’t conform as well. You can replace the image with image data or the image’s base64 representation (as String
).
I’ll show you the first option. I suppose you don’t want to write those if let
s every time, so let’s add two little extension
s to UIImage
and Data
that will speed up future conversions.
extension UIImage {
var data: Data? {
if let data = self.jpegData(compressionQuality: 1.0) {
return data
} else {
return nil
}
}
}
extension Data {
var image: UIImage? {
if let image = UIImage(data: self) {
return image
} else {
return nil
}
}
}
Change reminderItem
’s type from UIImage
to Data
.
From now on, when you need to access the image, write something like imageView.image = reminderGroup.reminderItem.image
. And when you need to save an instance of UIImage
to reminderItem
, write something like reminderGroup.reminderItem = image.data!
(the bang operator (exclamation mark) is needed because the computed property data
is optional).
Also make sure ReminderItem
does conform to Codable
. You didn’t provide the declaration of that type, so I can’t say whether it conforms of not.
How to add custom transient property in Codable struct
If you don't want to decode those 4 properties, just don't include them in the CodingKeys
(and don't forget to explicitly provide default values for them, so that the decoder can initialize the object properly):
struct VideoAlbum: Codable {
let id, image: String?
let video, mediaType: JSONNull?
let type, deleted, createdOn: String?
let modifiedOn: JSONNull?
var isPlaying: Bool? = nil
var currentTime: CMTime? = nil
var timeObserver: Any? = nil
var pausedByUser: Bool? = nil
enum CodingKeys: String, CodingKey {
// include only those that you want to decode/encode
case id, image, video
case mediaType = "media_type"
case type, deleted
case createdOn = "created_on"
case modifiedOn = "modified_on"
}
}
Cannot conform to Decodable when using Mirror(reflecting:)
Mirror
's init(reflecting:) initializer needs to pass an instance of your type to work.
You can accomplish what you are trying using a lazy variable, like this:
struct Sizes: Decodable {
let small: [SizeJSON]
let medium: [SizeJSON]
let large: [SizeJSON]
lazy var all: [SizeJSON] = {
Mirror(reflecting: self).children
.compactMap { $0.value as? [SizeJSON] }
.flatMap { $0 }
}()
}
That way you can both have access to self
instance and avoid for all
property to be decoded.
Is it possible to make an `any Protocol` conform to Codable?
Protocols do not conform to themselves, so any Wallet
is not itself Codable, and so you won't get an automatic conformance here, and you won't get automatic handling of arrays. But you can handle it yourself without trouble:
extension Account: Encodable {
enum CodingKeys: CodingKey {
case id
case name
case wallets
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(self.id, forKey: .id)
try container.encode(self.name, forKey: .name)
var walletContainer = container.nestedUnkeyedContainer(forKey: .wallets)
for wallet in wallets {
try walletContainer.encode(wallet)
}
}
}
If you comment-out wallets
temporarily, Xcode 14 will auto-complete the rest of the encode(to:)
method for you, so you only need to write the loop for wallets
.
This is something that may improve in the future. There's no deep reason that Swift can't auto-generate this conformance. It just doesn't today.
However, as Alexander notes, it is not in possible to conform to Decodable in a general way because it requires an init
. You have to know which type you want to decode, and the serialized data doesn't include that information (at least the way you've described it). So you'll have to make choices that you hand-write (for example, using some default Wallet type).
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.
Related Topics
Swift Safely Unwrapping Optinal Strings and Ints
How to Blur the Background in a Swiftui MACos Application
Swift String Permutations Allowing the Same Strings
How to Create an Uppercase Version of a String in Swiftui
Why Does Using Dynamictype on a Force Unwrapped Nil Optional Value Type Work
More Concise Way to Nest Enums for Access by Switch Statements in Swift
Can Not Conform to Protocol by Creating Extension with Where Clauses
Creating a Type Bound to a Certain Range in Swift
Swift. Get Binary String from an Integer
Generate Avaudiopcmbuffer with Avaudiorecorder
Unsafemutablepointer<Void> to Concrete Object Type
How to Understand What Is Causing a Crash Involving '_Nstouchbarfinderobservation'
Iterating Over an Nsorderedset
Having Trouble with Nstimer (Swift)
How to Make Embedded View Controller Part of the Responder Chain