I have to fulfill a protocol requirement that is defined in Objective-C like this:
@protocol AProtocol <NSObject>
+ (NSSet<Class> * _Nullable)someClasses;
@end
I want to implement this protocol in a subclass written in Swift. I want to return a Set of classes of another Object. The class I want to return is defined like this:
class B: NSObject {}
The class that conforms to the protocol is defined like this:
class A: NSObject, AProtocol {
static func someClasses() -> Set<NSObject>? {
return [B.self]
}
}
Why is NSSet<Class>
bridged to Set<NSObject>
instead of Set?
This solution is crashing, how can I solve the problem?
NSSet<Class>
is bridged to Set<NSObject>
because AnyClass
does not conform to Hashable
which is a precondition for the ValueType
of Set
.
It can be solved with the following extension for NSObjectProtocol
:
extension NSObjectProtocol where Self: NSObject {
static var objcClass: NSObject {
return (self as AnyObject) as! NSObject
}
}
This returns the class of the object casted as NSObject
. It is necessary to cast it first to AnyObject
because the type system of Swift is so strong that it would not compile or give a warning when directly casting a type to an instance type. In Objective-C this is fine because Class
is also just an object. Since NSObject
is implemented in Objective-C and the extension is just for NSObjectProtocol
, this is save to use (even with the force cast).
Implementing the extension on NSObjectProtocol
and not on NSObject
itself brings the positive effect that it is not exported to Objective-C.