Reputation: 3285
I am having difficulty performing type checking with Protocol type in Swift. I have a few protocols (defined in an obj-c framework) and am trying to inspect their type like so:
public func resolve(proto: Protocol!) -> NSObject {
// does not match when called with resolve(Foo)
if (proto is Foo)
{
return FooImpl();
}
// other type checking here
}
I have tried:
// Compile error: Expected member name or constructor call after type name
if (proto === Foo)
// Compile error: Expected member name or constructor call after type name
if (proto == Foo)
// Works, but seems hackish as it reverts to string comparison
if (NSStringFromProtocol(proto) == NSStringFromProtocol(Foo))
Can this be done without using NSStringFromProtocol
?
Upvotes: 1
Views: 131
Reputation: 299345
Protocol
is a runtime type, not an object. You need to use runtime functions on it.
public func resolve(proto: Protocol) -> NSObject {
if protocol_isEqual(proto, Foo.self) {
return FooImpl()
}
// other type checking here
}
That said, this is almost never the correct way to do things in Swift. If you really have to do this kind of work, you should use overloading:
func resolve(proto: Foo.Type) -> NSObject {
return FooImpl()
}
func resolve(proto: Any) -> NSObject {
return DefaultIfYouNeedOne()
}
Swift will pick the best overload. If you don't have an Any
version, that's better because then Swift won't let you pass unexpected types to resolve
.
But even this often suggests you're doing something you probably shouldn't be. Generally you should just add init()
to your protocol if you need to be able to construct the class. Or create a Constructible
protocol for things you can construct (or Resolvable
or whatever you need). Focus on the protocols, not the specific types. When you find yourself doing a lot of type checking, you're probably fighting Swift. You may have to in order to bridge to ObjC, but don't create more of that. Almost nothing in Swift should ever return NSObject
.
Unrelated note: you should not use Protocol!
in new functions. You probably copied it from something auto-imported from ObjC that hadn't been nullability audited. If you know it can't be nil, then use the type. If it can be nil, use an optional. There is seldom a reason to a pass a !
.
Upvotes: 4