Get the coding key for a keypath in Swift [closed] - swift

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
What I have: A codable struct with different properties.
What I want: A function, where I can get the exact name of the property when it is encoded in a Json. I think the most promising approach is using Keypath, but I have no idea how and whether it is possible at all. Thanks!

There is no way to do this out of the box, since there's no 1-1 mapping between properties of a Codable type and its coding keys, since there might be properties that aren't part of the encoded model or properties that depend on several encoded keys.
However, you should be able to achieve your goals by defining a mapping between the properties and their coding keys. You were on the right track with KeyPaths, you just need to define a function that takes a KeyPath whose root type is your codable model and return the coding key from said function.
struct MyCodable: Codable {
let id: Int
let name: String
// This property isn't part of the JSON
var description: String {
"\(id) \(name)"
}
enum CodingKeys: String, CodingKey {
case name = "Name"
case id = "identifier"
}
static func codingKey<Value>(for keyPath: KeyPath<MyCodable, Value>) -> String? {
let codingKey: CodingKeys
switch keyPath {
case \MyCodable.id:
codingKey = .id
case \MyCodable.name:
codingKey = .name
default: // handle properties that aren't encoded
return nil
}
return codingKey.rawValue
}
}
MyCodable.codingKey(for: \.id)

Related

Providing a default binding to String of an enum with rawValue type of String [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 days ago.
Improve this question
enum Tab : String {
case front, back
}
I would like to extend any enum that has raw value type of String to have an easily accessible bindingToString. Is there a way? Probably a protocol would have to be declared on any enum with String raw value type, but I have no idea how to do that. I'm looking for something like this:
enum Tab : String, BindableToString {
case front, back
}
var tab : Tab = .front
TextField(tab.bindingToString, ...)
However, we can create a Binding<Tab> extension to create a conversion to/from String:
extension Binding where Value == Tab {
var bindingToString : Binding<String> {
.init(get: { self.wrappedValue.rawValue }, set: { v in
if let newValue = Tab.init(rawValue: v) {
self.wrappedValue = newValue
}
})
}
}
This is almost fine, but first we need to explicitly create binding to Tab and then a binding to String, and we need to define this on every enum out there.
I was hoping we could somehow generalize this further so that we don't need to define explicitly a bindingToString on every such enum that has a raw value type of String; a protocol or a generic extension would do.
A solution utilizing the RawRepresentable idea from #loremipsum based on the proxy() func:
extension Binding where Value : RawRepresentable<String> {
var bindingToString : Binding<String> {
.init {
self.wrappedValue.rawValue
} set: { value in
if let newValue = Value(rawValue: value){
self.wrappedValue = newValue
}
}
}
}

Can you upload a custom struct to a Firestore using Swift [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 months ago.
Improve this question
I am creating an app where I have a custom struct called Piece. This piece has a string name, a string location, and a map/ dict. Is there a way to save this to Firestore?
Example code but this is what I will need to upload.
struct Piece {
name = 2222
location = "Drawer-1"
quantities = ["blue" : 1, "red" : 3]
}
This is my first post ever so sorry if I do things wrong format-wise.
yes - this is possible. I wrote a long blog post about this: Mapping Firestore Data in Swift - The Comprehensive Guide.
In your case, here is how you would do this:
First, make your struct (and the Quantity struct) codable:
struct Piece: Codable {
#DocumentID var id: String?
var name: Int // are you sure that a field containing a number like 2222 should be called "name"?
var location: String
var quantities: [Quantity]
}
struct Quantity: Codable {
var color: String
var amount: Int
}
Then, create a class for accessing Firestore. You can name it PieceStore or PieceRepository, whatever you like.
class PieceStore {
func addPiece(piece: Piece) {
let collectionRef = db.collection("pieces")
do {
let newDocReference = try collectionRef.addDocument(from: piece)
print("Piece stored with new document reference: \(newDocReference)")
}
catch {
print(error)
}
}
}
See the blog post for more details about fetching data using one-time fetches and snapshot listeners (which will give you that cool real-time sync that Firestore is famous for).

Response struct does not like CodingKeys [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 1 year ago.
Improve this question
I have this struct used to decode a JSON coming from the server:
struct AdminResponse: Codable {
let Status: Int?
let SuperUsers: [SuperUser]?
let Message: String?
}
struct SuperUser: Codable {
let name:String?
let id:String?
}
This works perfectly. I am able to decode the JSON.
But I don't like these properties with the first uppercase, then I do
struct AdminResponse: Codable {
let Status: Int?
let SuperUsers: [SuperUser]?
let Message: String?
enum CodingKeys: String, CodingKey {
case status = "Status"
case superUsers = "SuperUsers"
case message = "Message"
}
}
struct SuperUser: Codable {
let name:String?
let id:String?
enum CodingKeys: String, CodingKey {
case name = "name"
case id = "id"
}
}
Error: Type AdminResponse does not conforme to protocol Decodable.
Why???
From the documentation Encoding and Decoding Custom Types:
Codable types can declare a special nested enumeration named
CodingKeys that conforms to the CodingKey protocol. When this
enumeration is present, its cases serve as the authoritative list of
properties that must be included when instances of a codable type are
encoded or decoded. The names of the enumeration cases should match
the names you've given to the corresponding properties in your type.
In other words:
struct CodableStruct: Codable {
let myPropertyName: SomeCodableType
enum CodingKeys: String, CodingKey {
case myPropertyName = "WhateverIsMatchingInRealityTheJSON"
}
}
And it's mandatory that myPropertyName be the name of the var of CodableStruct AND the name of the case of the CodingKeys.
In your case, since it's recommended to name the var starting with a lowercase, I'll go that way:
struct AdminResponse: Codable {
let status: Int?
let superUsers: [SuperUser]?
let message: String?
enum CodingKeys: String, CodingKey {
case status = "Status"
case superUsers = "SuperUsers"
case message = "Message"
}
}

Am I able to add a member-wise initializer to a Codable-conforming object? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
I currently have a class that conforms to Codable and has an initializer like so
public class A: Codable {
var aString: String?
public init(input: String?) {
self.aString = input
}
}
When I try to create an instance of it, I get an error
let myA = A(input: "Goodbye world")
Incorrect argument label in call (have 'input:', expected 'from:')
Am I restricted to only the init(from decoder: Decoder) throws initializer for Codable classes?
Your code is correct, double check whether you actually have a public initializer not a private one.
I put this into my Xcode Playground and everything works as expected:
public class A: Codable {
var aString: String?
public init(input: String?) {
self.aString = input
}
}
let a = A(input: "123")

Value type of string? Has no member components. (Struct) [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 5 years ago.
Improve this question
I look at each thread but can't find any solution for my case.
I have a model:
import Foundation
public struct Destinos: Data {
public var idDestino : Int?
public var desDestino : String?
public func dictionary() -> NSDictionary {
let dictionary = NSMutableDictionary()
dictionary.setValue(self.idDestino, forKey: "idDestino")
dictionary.setValue(self.desDestino, forKey: "desDestino")
return dictionary
}
}
So I want to change the desDestino "string" to [String] to use later and show in at tableView. For this.I write this line of code in another file.swift:
var cadena = Destinos()
cadena.desDestino = "HOLA, nada, algo, otra, cosa, mas que eso"
let array = cadena.desDestino.components(separatedBy: ", ") // in this line i get the error: value type of string? has no member components.
so... what is the problem?
There's no reason to use NSDictionary here. Just use a native Swift dictionary (with a literal).
public struct Destinos {
public let idDestino : Int?
public let desDestino : String?
public func toDictionary() -> [String: Any?] {
return [
"idDestino": idDestino,
"desDestino": desDestino
]
}
}
As for generating your array, you have two issues:
1. components(seperatedBy:) is misspelt
2. cadena.desDestino is an is a String? (Also known as a Optional<String>) which hasn't been unwrapped. The nicest way to take care of this is to use optional chaining, and then use nil coalescence (??) to make it an empty array in the case cadena.desDestino is nil.
var cadena = Destinos(
idDestino: 123,
desDestino: "HOLA, nada, algo, otra, cosa, mas que eso"
)
let array = cadena.desDestino?.components(separatedBy: ", ") ?? []