1

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 }
    }
horseshoe7
  • 2,745
  • 2
  • 35
  • 49

2 Answers2

4

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()
    }
Nazmul Hasan
  • 10,130
  • 7
  • 50
  • 73
horseshoe7
  • 2,745
  • 2
  • 35
  • 49
0

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.

OhadM
  • 4,687
  • 1
  • 47
  • 57
  • Your one method looks great. How does this work within the bounds of what I'm trying to accomplish? Imagine a NSFetchedResultsController managing specific subclasses of NSManagedObject. So I know the type of object it is managing, but say I don't have an instance. I want to know if it's class conforms to InteractivelyNameable, and if so, give me an UIAlertController. – horseshoe7 Sep 15 '17 at 14:40
  • I think that your problem is that you work with concrete types. You shouldn't work with concrete types but for example, with an array of Nameable protocol, this way you know the actual protocol type. Of course, if you use concrete types, you will have type issues validation. The solution you wrote in your answer violates the LSP principle from SOLID btw.. – OhadM Sep 15 '17 at 15:08
  • what on earth is the LSP principle from SOLID? I have to work with concrete types right now. – horseshoe7 Sep 15 '17 at 16:05
  • LSP: https://softwareengineering.stackexchange.com/questions/170138/is-this-a-violation-of-the-liskov-substitution-principle If concrete types is what you need then the generic example I gave you would work flawlessly. – OhadM Sep 16 '17 at 10:40