Using Reflections API (Mirror) with SwiftUI?

Hi,

I am new to SwiftUI and am wanting to iterate over a class and present in a view the keyname and keyvalue. I understand from googling that I need to use something like the reflections API to achieve this but am struggling to convert the swift example to work with swiftui.

My current non-working code:

import SwiftUI

struct ShowClassData: View {
    @ObservedObject var myClass : MyClass
    
    var body: some View {
        VStack{
            var mirror = Mirror(reflecting: myClass)
            
            mirror.children.forEach({
                Text("\(child.label): \(child.value)")
            })
        }
    }
}

Get this error:

  • Type '()' cannot conform to 'View'; only struct/enum/class types can conform to protocols

I've also tried the following with no luck:

for case let (label?, value) in mirror.children {
    print (label, value)
}

Different error:

  • Closure containing control flow statement cannot be used with function builder 'ViewBuilder'

The problem is that mirror.children.forEach does not return anything that conform to the SwiftUI View protocol, in fact it doesn't return anything as forEach is a void-returning function. You should use ForEach instead:

struct ShowClassData: View {
    @ObservedObject var myClass : MyClass

    var body: some View {
        VStack {
            let mirror = Mirror(reflecting: myClass)
            ForEach(Array(mirror.children), id: \.label) { child in
                Text("\(child.label!): \(String(describing: child.value))")
            }
        }
    }
}
3 Likes

Oh that's awesome thank you. Now, all I need to do is clean that output up as it's not very user friendly.

[(label: Optional("_varA1_completeDate"), value: Combine.Published<Swift.Optional<Foundation.Date>>(storage: Combine.Published<Swift.Optional<Foundation.Date>>.Storage.value(Optional(2021-01-15 09:41:07 +0000)))), (label: Optional("_varA2_images"), value: Combine.Published<Swift.Array<SwiftUI.Image>>(storage: Combine.Published<Swift.Array<SwiftUI.Image>>.Storage.value([SwiftUI.Image(provider: SwiftUI.ImageProviderBox<__C.UIImage>)]))), (label: Optional("_varA2_completeDate"), value: Combine.Published<Swift.Optional<Foundation.Date>>(storage: Combine.Published<Swift.Optional<Foundation.Date>>.Storage.value(Optional(2021-01-15 09:41:12 +0000)))), (label: Optional("_varA2_switchesOff"), value: Combine.Published<Swift.Bool>(storage: Combine.Published<Swift.Bool>.Storage.value(true))), (label: Optional("_varA3_completeDate"), value: Combine.Published<Swift.Optional<Foundation.Date>>(storage: Combine.Published<Swift.Optional<Foundation.Date>>.Storage.value(nil))), (label: Optional("_varA4_completeDate"), value: Combine.Published<Swift.Optional<Foundation.Date>>(storage: Combine.Published<Swift.Optional<Foundation.Date>>.Storage.value(Optional(2021-01-15 09:41:13 +0000)))), (label: Optional("_varA5_completeDate"), value: Combine.Published<Swift.Optional<Foundation.Date>>(storage: Combine.Published<Swift.Optional<Foundation.Date>>.Storage.value(Optional(2021-01-15 09:41:14 +0000)))), (label: Optional("_varA6_completeDate"), value: Combine.Published<Swift.Optional<Foundation.Date>>(storage: Combine.Published<Swift.Optional<Foundation.Date>>.Storage.value(Optional(2021-01-15 09:41:15 +0000))))]