Reputation: 2817
Say I have:
@objc public protocol InteractivelyNameable: Nameable {
static func alertViewForNaming(_ existingObject: Nameable?,
context: NSManagedObjectContext,
completion:@escaping ((_ success: Bool, _ object: Nameable?, _ didCancel: Bool, _ error: Error?) -> Void)) -> UIAlertController?
}
And I have a generic view controller that manages various types (generic type is .fetchableObjectType... basically NSManagedObject.self
.. well, a subclass of it). I need to check if a specific object type conforms to the protocol, and if so, invoke it.
something like:
// valid swift code
if self.dataSource.fetchableObjectType is InteractivelyNameable {
// not valid swift code
if let alert = (self.dataSource.fetchableObjectType as! InteractivelyNameable).alertViewForNaming(....) { // ... do stuff }
}
Upvotes: 1
Views: 2699
Reputation: 4803
The static method you wrote isn't generic but protocol as type parameter. Basically, when you use as a protocol type parameter and not the generic form you force the compiler to use the dynamic dispatcher, ergo, Objective-C.
What you need to do in order to use the statically type dispatcher (Swift):
static func alertViewForNaming<T : Nameable>(_ existingObject: T,
context: NSManagedObjectContext,
completion:@escaping ((_ success: Bool, _ object: T, _ didCancel: Bool, _ error: Error?) -> Void)) -> UIAlertController?
This is, a generic type constraint method and in this case, it's protocol type constraint AKA Nameable
.
You invoke the static method as follows:
let test : ObjectThatConformsToNameableProtocol = InteractivelyNameable.alertViewForNaming.....
This way, the compiler can infer the type for the generic type method which in this case, ObjectThatConformsToNameableProtocol
.
I didn't test the code but it's important to understand the difference between generics and protocol type parameter.
Upvotes: 0
Reputation: 2817
To cast a Type to a Protocol at a "Class Level", you can use the .Type property of the protocol itself.
if let type = self.dataSource.fetchableObjectType as? InteractivelyNameable.Type {
if let alert = type.alertViewForNaming(nil, context: self.dataSource.managedObjectContext, completion: completion) {
// this code finds itself inside a UIViewController subclass...
self.present(alert, animated: true, completion: nil)
return
}
}
Summary in Generic Form:
if let myConformingObject = someObject as? InteractivelyNameable {
// invoke instance methods...
myConformingObject.someInstanceMethodDefinedInProtocol()
// invoke class methods
type(of: myConformingObject).someClassMethodDefinedInProtocol()
}
// i.e. someTypeParameter = NSManagedObject.Type
if let conformingType = someTypeParameter as? InteractivelyNameable.Type {
conformingType.someClassMethodDefinedInProtocol()
}
Upvotes: 4