struct SomeStruct<T> {
var value: T
var closure: (T) -> Any
}
I'm using reflection and want to call closure with parameter value in runtime:
let str = SomeStruct<String>(value: "abc", closure: { $0 })
let mirror = Mirror(reflecting: str)
callClosure(mirror: mirror)
func callClosure(mirror: Mirror) {
guard let value = mirror.descendant("value"),
let closure = mirror.descendant("closure")
else { return }
if let castedClosure = closure as? (Any) -> Any {
print("How to cast to an unknown inner type to get here?")
castedClosure(value)
}
if let castedClosure = closure as? (String) -> Any,
let castedValue = value as? String {
print("Succeeds for SomeStruct<String>")
castedClosure(castedValue) // works
}
}
Since the type of value and parameter of the closure is always the same (although unknown), it should always be legit to call closure with value as a parameter.
How can we either cast the closure properly to make the compiler happy, or call the closure directly silencing the type-check system?
I've tried so far casting with unsafeBitcast(_:to:) and unsafeDowncast(_:to:), with no luck
struct DifferentStruct {
var value: Int
var closure: (String) -> Any
}
let str2 = DifferentStruct(value: 1, closure: { $0 })
let mirror2 = Mirror(reflecting: str2)
callClosure(mirror: mirror2)
When you converted your value to a Mirror you deleted the type information. You cannot get it back from the thin air. At this point nothing guarantees that the types match
Look, I'm writing a unit testing library for SwiftUI, and I have a good reason for asking how to do exactly what I've asked. I know this is unsafe and bad design and so on, but I don't have other choice!
SomeStruct is a very simplified example of the problem, and I don't have access to it
Unfortunately, this doesn't work in my case. SomeStruct is defined in external framework (SwiftUI) and its instance variables are all private and visible in the reflection only
You can still use the same technique, extending the struct with reflection-based logic to find and invoke the closure. Within the struct's own context, you'll have access to its generic parameters so you can cast to the function type you expect.
At first, I thought this could work but then realized - the reference to the SomeStruct is of type Any as well. So I'd still need to cast struct of type Any to specific SomeStruct<TYPE> before invoking the method from the extension. SomeStruct<type(of: value)> would do the trick, but it's not a valid code
The way I would factor it is to make the type conform to a protocol with a type-erased interface, and put the generic type specific logic in the conformance.