Using Mirror to access value of a property of an optional property of self

This might like a puzzle or educational/investigational purposes but actually it is a part of an app I work on ... Please consider these two structs:

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
}

Container1, Container2, ... ContainerN have a property responseId: String (ContainerBase protocol).

OtherA, OtherB, AnotherA, AnotherB are completely unrelated (unrelated to each other and unrelated to parent ContainerN) ... In ContainerN I might have only one inner struct in other ContainerM I might have up to 8 inner unrelated structs. This varies in each case.

All inner structs have a property: "let contactId: String". (No protocol defined yet but I could define one if it is helpful)

My mission:

Get value of property "contactId" of a inner struct whose property name is same as value of property "responseId" of Container.

Example:

let container1 = Container1(
    responseId: "otherA",
    otherA: Container1.OtherA(contactId: "123", cats: ["figaro"]),
    otherB: nil)
container1.findContactId() // expected "123"

let container2 = Container2(
    responseId: "anotherB",
    anotherA: Container2.AnotherA(contactId: "777", passed: true),
    anotherB: nil)
container2.findContactId() // expected <nil>

So at first I was writing a function like this in all containers but now I have dozens of dozens (and increasing) of container structs.... in some of them I made some typos and got bugs in the way ... This is getting out of control.

extension Container1 {
    func findContactId() -> String? {
        switch responseId {
        case "otherA": return otherA.contactId
        case "otherB": return otherB.contactId
        }
    }
}

So I tried to implement this with reflexion but I cannot make it work without generating a warning. Could you guide me on how to find a stable solution without warnings?

My ugly code ahead (works but with a warning):

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
    }
}
func findContactId() -> String? {
		Mirror(reflecting: self)
			.children
			.first(where: { $0.label == responseId })
			.map(\.value)
			.flatMap(Mirror.init(reflecting:))?
			.children
			.first(where: { $0.label == "some" })
			.map(\.value)
			.flatMap(Mirror.init(reflecting:))?
			.children
			.first(where: { $0.label == "contactId" })?
			.value as? String
	}

This doesn't warn. I'm pretty sure you could avoid the multiples Mirrors as you know the structure you are after

1 Like
Terms of Service

Privacy Policy

Cookie Policy