struct JSONAPIResponse<D: Decodable, M: Decodable>: Decodable {
let data: D
let meta: M?
}
I have struct which takes 2 generic types. But 2nd type(M) should be optional. I mean that I want to use this block of code without error:
JSONAPIResponse<DatumEntity>
But now should use pattern:
JSONAPIResponse<DatumEntity, MetaEntity>
So question, how to refactor JSONAPIResponse struct, after that I can use JSONAPIResponse code without error
Related
I want to make record of 4 different types. I have the following code
import GRDB
enum RecordType: Int16 {
case video, image, text, rep
}
extension RecordType: DatabaseValueConvertible {}
struct Record: Codable, FetchableRecord, PersistableRecord {
var id: Int64?
var type: RecordType
}
Right now it complains Type 'Record' does not conform to protocol 'Decodable'
Of course when I remove the type from the struct, that complaint goes away. Since type is technically Int16 why does this make it not Decodable?
When I adopt Codable to the RecordType as well this goes away. Found the answer here
extension RecordType: DatabaseValueConvertible, Codable {}
I am trying to create a new instance of a codable struct
#State private var parcel = Parcel()
but I'm getting this error:
Missing argument for parameter 'from' in call
Insert 'from: <#Decoder#>'
struct Parcel: Codable {
var created_at: String
var height: Double
var id: String
var length: Double
var mode: String?
var object: String
var predefined_package: String?
var updated_at: String?
var weight: Double
var width: Double
}
Every object in Swift needs an initializer: some code to set up the object when it is first created. If your object is an instance of a class, the initializer needs to be explicitly defined by you. However if the object is an instance of a struct, Swift implicitly defines an initializer. For example, this struct
struct Foo {
let bar: Int
}
implicitly gets an initializer that looks like this
init(bar: Int) {
self.bar = bar
}
Initializers can also be implicitly created through protocol extensions. That means if your struct inherits a protocol (such as Codable), the protocol can define additional initializers for you. For this simple example, Codable would add something like this
init(from decoder: Decoder) throws {
// decode a key value pair with name "bar" and an Int value using decoder
let decodedBar = try ...
self.init(bar: decodedBar)
}
In your case, when you write parcel = Parcel() you are calling this kind of initializer
init() {
// initialize somehow with no input!
}
But you never defined anything like that! The compiler is suggesting that you call the initalizer you got from Codable since it's a close match, but that's probably not what you want either.
You can either define that missing initializer, or define default values for all of your struct's members. If you do that, the implicit initializer defined by Swift will have no arguments, making your code valid. For example
struct Foo {
let bar: Int = 3
}
let f = Foo() // now this is valid, implicit init has no arguments
By default, structs create an initialiser behind the scenes for every non-optional property that you declare. So by simply creating an instance of the struct you need to include all non-optional values it requires. If you don’t want to add the values when you initialise it, change them to vars and make them optional (add ? to the end).
So I am getting a warning (and I can't dismiss it because it won't run the JSON if I do)
The warning is for the following
struct Station: Codable, Identifiable {
let id = UUID() // WARNING: Immutable property will not be decoded because it is declared with an initial value which cannot be overwritten
var name : String
var imageurl : String
var listenlive : String
}
The problem is the following
I can't make it UUID as I get the following error
Type 'Station' does not conform to protocol 'Decodable'
// STATION
struct Sdata: Codable {
var data: [Station]
}
struct Station: Codable, Identifiable {
let id = UUID
var name : String
var imageurl : String
var listenlive : String
}
Also technically the let id is wrong because the JSON has it as _id
"_id":"5f52ed668b964609655b48d1"
So How do I make the warning go away while conforming to the correct value type?
In this case, it's not a matter of "getting rid of the warning". What you are doing seems fundamentally wrong.
The way you declared struct Station, every time a new struct is created, its "id" field is set to a new UUID, that is every struct Station has a different id field, that cannot be changed afterwards.
So if we ignore Codeable for the moment, how would you write such a struct to a file and read it back later, getting the same id? Answer: You can't read it back. At some point you create a struct Station with a new, different UUID, and there is no way to store the one that you wrote to a file. So you have a problem here.
So the problem is quite obvious: If you have a "let" property with a non-constant value, Codeable would have to write it, but Decodable cannot read it, so you have a problem. Make "id" a var, possibly with a constructor that sets it to a new UUID, but it must be changeable.
You need to change it to id:String and use enum CodingKeys for the custom name _id
struct Station: Codable , Identifiable {
var id,name,imageurl,listenlive:String
private enum CodingKeys : String, CodingKey {
case id = "_id", name , imageurl , listenlive
}
}
This question already has answers here:
Protocol extending Encodable (or Codable) does not conform to it
(3 answers)
Closed 2 years ago.
Below code compiles fine (Swift 5.0+)
import Foundation
protocol PriceType: Codable {
var value: Double {get set}
var currency: String {get set}
}
struct Price: PriceType {
var value: Double
var currency: String
}
struct Quantity: Codable {
var value: Double
var unit : String
}
struct Commodity: Codable {
var price: Price
var quantity: Quantity
}
The moment I change the definition of Commodity to below, the code doesn't compile.
struct Commodity: Codable {
var price: PriceType
var quantity: Quantity
}
The only change I made is that I made price property of the type PriceType.
I get below error
error: 019 - Codeable v2.xcplaygroundpage:20:8: error: type 'Commodity' does not conform to protocol 'Decodable'
struct Commodity: Codable {
^
019 - Codeable v2.xcplaygroundpage:21:9: note: cannot automatically synthesize 'Decodable' because 'PriceType' does not conform to 'Decodable'
var price: PriceType
^
error: 019 - Codeable v2.xcplaygroundpage:20:8: error: type 'Commodity' does not conform to protocol 'Encodable'
struct Commodity: Codable {
^
019 - Codeable v2.xcplaygroundpage:21:9: note: cannot automatically synthesize 'Encodable' because 'PriceType' does not conform to 'Encodable'
var price: PriceType
As per Apple Documentation
The simplest way to make a type codable is to declare its properties
using types that are already Codable. These types include standard
library types like String, Int, and Double; and Foundation types like
Date, Data, and URL. Any type whose properties are codable
automatically conforms to Codable just by declaring that conformance.
Since PriceType conform to Codable as its two properties i.e. value and currency are by default Codable then why code fails to compile if I made the price property of type PriceType (protocol) instead of Price (struct)??
Protocols do not conform to themselfs or protocols they inherit, see: Protocol extending Encodable (or Codable) does not conform to it. This won't be fixed, see: https://bugs.swift.org/browse/SR-5853?page=com.atlassian.jira.plugin.system.issuetabpanels%3Achangehistory-tabpanel
I think what you actually want is something like this:
struct Commodity<T: PriceType>: Codable {
var price: T
var quantity: Quantity
}
let ContentData be a class that is intended to be subclassed and create a struct that will hold on to some generic properties...
struct Properties<T: ContentData, U: Paged<ContentData>> {
let contentDataSubclass: T
let pagedContentData: U
}
Instantiate like so:
let properties = Properties<FAQ, Paged<QuestionAnswer>>(contentData: faq!, contentDataProperty: faq!.questionAndAnswers)
Note: Both FAQ and QuestionAnswer are subclasses of ContentData
The compiler complains saying:
error: 'Properties' requires that 'Paged<QuestionAnswer>' inherit from 'Paged<ContentData>'
Do I need a where clause of my Properties struct to specify that my object of type U is also of generic type? How does this work?
The goal is to write a struct definition that will accept multiple levels of generics. Maybe something like:
struct Properties<T: ContentData, U: Paged<V: ContentData>>