简体   繁体   中英

How to call a static method of a generic type conforming to a protocol in Swift

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 }
    }

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()
    }

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM