I am trying to create a model object to store json data received from newsAPI. However one of the keys called description matched a reserved keyword in swift. How do I resolve this ? The error message read Error Message: Property 'description' with type 'String?' cannot override a property with type 'String'
class ArticlesData: NSObject {
var author: String?
var title: String?
var description: String?
var publishedAt: String?
var urlImage: String?
var urlWebsite : String?
}
author : Andrew Marino
title : Vergecast: this week’s Section 230 hearing and the season of weird gadgets
description : Nilay, Dieter, and Adi discuss the latest Section 230 congressional hearing featuring the CEOs of Big Tech. Ashley Carman stops by to talk about how gadget makers are turning to shopping channels to market their products.
url : https://www.theverge.com/2020/10/30/21541796/section-230-hearing-gadgets-qvc-razr-2020-review-vergecast-podcast-428
urlToImage : https://cdn.vox-cdn.com/thumbor/sgk9rqbUKhLVhNxKunmuX_Zm6TM=/0x146:2040x1214/fit-in/1200x630/cdn.vox-cdn.com/uploads/chorus_asset/file/19749210/vpavic_200214_3909_samsung_galaxy_Z_flip_0013.jpg
publishedAt : 2020-10-30T14:44:14Z
content : Photo by Vjeran Pavic / The Verge\n\n This week on The Verge’s flagship podcast, The Vergecast: Sen. Ted Cruz (R-TX) yells at Twitter CEO Jack Dorsey, gadget makers are going to QVC, and it is weird ph… [+3098 chars]
Simplest solution: Use a struct, neither a class or even a subclass of NSObject is necessary.
struct ArticlesData {
Otherwise just use a different name.
If you are going to decode the JSON with Decodable add CodingKeys to map the dictionary key to the struct member with a different name.
And don't declare all properties carelessly as optional. Declare only those as optional which can be nil.
I've run into the same 'issue' several times and it's quite annoying indeed. You should rename your property to something else.
How are you mapping your JSON into the object? If you use Codable, you can use custom CodingKeys such as:
class ArticlesData: NSObject, Codable
{
var author: String?
var title: String?
var myDescription: String?
var publishedAt: String?
var urlImage: String?
var urlWebsite: String?
private enum CodingKeys: String, CodingKey
{
case author, title, myDescription = "description", publishedAt, urlImage = "urlToImage", urlWebsite = "url"
}
}
EDIT: As vadian said, you can also use a struct. I actually prefer that solution over renaming the propery to another name than you want.
Related
I'm in process of adding Core Data to my app, started out with a struct like this:
struct Expense: Equatable{
let id: String = UUID().uuidString
var name: String
var description: String
var category: String
var nextBill: Date
var billingCycle: (Int, String)
var currency: Currency?
var price: Decimal
}
Reading documentation look like I'll need to convert it to a class
#objc(Expense)
public class Expense: NSManagedObject {
let id: String = UUID().uuidString
var name: String
var description: String
var category: String
var nextBill: Date
var billingCycle: (Int, String)
var currency: Currency?
var price: Decimal
}
However this appears to have issue with the billingCycle property which is a tuple value ( example of value: 1 per week, 1 per month, 3 per year)
I'm thinking of splitting the billingCycle property into 2 new properties: billingCycleInt and billingCycleString. Would this be the best approach or there is other way?
That would be best. Core Data is— internally— still very much oriented toward Objective-C. As such it has no idea about Swiftisms like tuples. There are other approaches that could work, like trying to get NSCoding to work for this property, but they would all be significantly more complex.
If you’d like to keep the tuple, you might consider adding the two properties you mention and then converting the tuple into a computed property that looks up the values of the other two. Then you can use a Swift tuple where it’s convenient but still work with Core Data.
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 {}
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
}
}
I'm trying to initialise a value in dictionary as follow,
var og:image: String
But after og: it tries to assign the type considering og as the variable to site_name, which is obviously wrong.
Is there a way to assign og:image as variable to String type using
special or escape characters?
In reference to this, apple does not provide any meaningful explanations to variable naming conventions in such a situation.
Edit-1:
Here is code snippet to clarify dictionary usage is in JSON parsing data structure,
struct Metadata: Decodable{
var metatags : [enclosedTags]
}
struct enclosedTags: Decodable{
var image: String
var title: String
var description: String
var og:site_name: String
}
You cannot use : (colon). But if you really want:
var ogCOLONimage: String
Joking apart. You could use a Dictionary or something like that:
var images: [String: String] = ["og:image" : "your string"]
Now you can access your og:image data with images["og:image"].
Swift allow you to use almost any character when naming variables. You can even use Unicode characters.
However, there are a few restrictions:
Constant and variable names can’t contain whitespace characters, mathematical symbols, arrows, private-use (or invalid) Unicode code points, or line- and box-drawing characters. Nor can they begin with a number, although numbers may be included elsewhere within the name.
Said that, it is not possible to use : in the name of a variable. However, you can use a Unicode character similar to that symbol. Depending on what you want it for, this may be a valid solution.
Here you have a list of the Unicode characters similar to : that can be used in the name of a variable:
︓
﹕
:
(https://www.compart.com/en/unicode/based/U+003A)
Based on the example you provided it would be this:
struct Metadata: Decodable{
var metatags : [enclosedTags]
}
struct enclosedTags: Decodable{
var image: String
var title: String
var description: String
var og:site_name: String
}
Turns out swift has it's own feature in terms of naming specificity of variables in structs i.e. CodingKeys, so in terms for me the below naming convention worked,
struct Metadata: Decodable{
var metatags: [enclosedTags]
}
struct enclosedTags: Decodable{
let image: String
let title: String
let description: String
let siteName: String
private enum CodingKeys : String, CodingKey{
case image = "og:image", title = "og:title", description = "og:description", siteName = "og:site_name"
}
This was rightfully pointed out by #hamish in comments (Thanks mate!)
In Swift, say for example I have a struct for this model:
struct Message {
var message: String = ""
var timestamp: String = ""
var id: String = ""
}
And I would be instantiating multiple Messages using this struct from a database, and then populate a TableView with them.
Would it be best practice to using optionals instead of setting these variables with empty strings like such?
struct Message {
var message: String?
var timestamp: String?
var id: String?
}
Would it be more efficient to basically setting the variables to nil vs an empty string? Does nil take less memory vs empty string?
Before thinking about optimization, you have to ask yourself the good question: is there any chance that Message may contain optionals for one or several of its properties? If yes, use optionals, if no, don't use optionals.
Then, if you want to improve your code, you can use memberwise initializer for your struct:
struct Message {
var message: String
var timestamp: String?
var id: String
}
let message = Message(message: "Some message", timestamp: nil, id: "Id14")
Finally, I doubt any memory optimization on Struct (with optional or non optional properties) will give any significant improvement to your app/project.
Avoid optionals whenever it is possible. Stored properties are not as magical as they are in objective-c. Just give them default values if it is appropriate.