I have a large numbers of structs and all of them have responseId: String
and there is a property with same name as the value of responseId
that contains contactId: String
.
responseId
is always non-optional String.contactId
of inner object is also non-optional String- all inner objects are optional (at runtime only one of the objects will be non-nil)
Below are two examples:
protocol ContainerBase {
var responseId: String { get }
}
struct Container1: ContainerBase {
struct OtherA {
let contactId: String
let cats: [String] // Other info here, not related to OtherB
}
struct OtherB {
let contactId: String
let dogsNum: Int // Other info here, not related to OtherA
}
let responseId: String
let otherA: OtherA? // Optional
let otherB: OtherB? // Optional
}
struct Container2: ContainerBase {
struct AnotherA {
let contactId: String
let passed: Bool // Other info here, not related to AnotherB
}
struct AnotherB {
let contactId: String
let friend: String // Other info here, not related to AnotherA
}
let responseId: String
let anotherA: AnotherA? // Optional
let anotherB: AnotherB? // Optional
}
Question:
How can I access contactId
from Container1
or Container2
dynamically? (I tried the non dynamic approach with an extra function for each ContainerN struct with a switch inside but this is getting crazy because I have too many this structs, I already made some typos and forgot some cases, caused bugs,... and I imagine the reliable solution is "reflexion"?).
Example:
For example, if responseId
of Container1
is "otherA" then I should look for contactId
inside of property otherA
. Since I have several types of Containers with different types of unrelated inner objects each one, solution should not be specific to Container1 nor Container2 it should work with any ContainerBase
.
I implemented a dirty code but it causes a warning and cannot find to work it without generating one. Also I think this does not work reliably (This is for my iOS app but this strangely this does not work in linux Swift). Is this even possible? or it is a compiler glitch?
let c1 = Container1(
responseId: "otherA",
otherA: Container1.OtherA(contactId: "123", cats: ["figaro"]),
otherB: nil)
c1.findContactId() // expected "123"
Ugly code ahead:
extension ContainerBase {
func findContactId() -> String? {
let mirror = Mirror(reflecting: self)
guard let tInnerRes = mirror.children.first(where: { $0.label == self.responseId })?.value else { return nil }
// WARN: Conditional cast from 'Any' to 'Optional<Any>' always succeeds
guard let maybeInnerRes = (tInnerRes as? Optional<Any>) else { return nil }
guard let innerRes = maybeInnerRes else { return nil }
let innerMirror = Mirror(reflecting: innerRes)
let contactId = innerMirror.children.first(where: { $0.label == "contactId" })?.value as? String
return contactId
}
}
Any help is appreciated
Aucun commentaire:
Enregistrer un commentaire