Given that the underlying types are the same, I expected test2 to be true, not false:
protocol Foo {}
class Bar: NSObject, Foo {}
class Test {
func testCompare() {
let b = Bar()
let test1 = compare(expected: Bar.self, actual: b)
let c: Foo = b
let test2 = compare(expected: Bar.self, actual: c)
/*
(lldb) p expected
(@thick NSObject.Type) $R0 = SpokestackTests.Bar
(lldb) p type(of: actual).self
(SpokestackTests.Foo.Type) $R2 = SpokestackTests.Bar
*/
print(test1, test2) // true false
}
func compare<T>(expected: NSObject.Type, actual: T) -> Bool {
return expected == type(of: actual).self
}
}
Is this due to the difference between a concrete metatype of a class vs the existential metatype of a protocol instance?
After taking a look at the documentation of type(of:) function we can rephrase the last paragraph to something like this:
This unexpected result occurs because the call to
type(of: value)insidecompare(expected:actual:)must return a metatype that is an instance ofT.Typewhich is the static type ofactualparameter (Foo.self). To get the dynamic type inside value in this generic context, cast the parameter to Any when calling type(of:).
or just change the compare(expected:actual:) function to use Any type instead of generics:
private func compare(expected: NSObject.Type, actual: Any) -> Bool {
return expected == type(of: actual).self
}
Update: Even better you can use @Jessy suggestion in the comments
func compare<Expected: Foundation.NSObject>(expected: Expected.Type, actual: Any) -> Bool {
return type(of: actual) is Expected.Type
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With