Getting the string representation of the protocol dynamically

I'm looking for a way to dynamically get the protocol name from a protocol type without using an attribute @objc

in the protocol declaration.

I know this works:

func keyForProtocol(aProtocol: Protocol) -> String {
    return NSStringFromProtocol(aProtocol)
}

      

but only if the protocol has the attribute @obj

:

@objc protocol Test {}

var key = keyForProtocol(Test.self)  // Key contains "TestApp.Test"

      

however, as soon as I remove the attribute @objc

, compilation fails with an error:

'Test.Protocol' is not convertible to 'Protocol'

      

Is there a way to achieve this?

Note: The reason I want to avoid @objc

is because it doesn't allow bound types (i.e. generics in the protocol) - in these cases, compilation fails with this error:Method cannot be marked @objc because the type of parameter xx cannot be represented in Objective-C

+3


source to share


2 answers


I recently found a solution by executing the method keyForProtocol

like this:

func keyForProtocol<P>(aProtocol: P.Type) -> String {
    return ("\(aProtocol)")
}

      

It works with any type, not just protocols, but I'm fine with it.



Some examples from the playground:

protocol Test {}
keyForProtocol(Test.self) // Prints "__lldb_expr_92.Test"

class MyClass {}
keyForProtocol(MyClass.self) // Prints "__lldb_expr_92.MyClass"

keyForProtocol(Int.self) // Prints "Swift.Int"

keyForProtocol(UIView.self) // Prints "UIView"

      

+2


source


As Antonio said:

let protocolDescription = "\(aProtocol)"

      

will return the (sometimes weird) protocol name.

I finally finished my task by converting this string to a protocol with:

let protocolReference = NSProtocolFromString(protocolDescription)

      



This method is ideal if you need to get the protocol type from a generic parameter, as in this example (lightweight / home dependency manager):

class DependencyManager<T> {
  private static func inject(_ aProtocol: T.Type) -> T {
    let application = UIApplication.shared.delegate as! LMApplication
    let dependencies = application.applicationDependencies

    let protocolReference = NSProtocolFromString("\(aProtocol)")
    let dependency = dependencies!.object(for: protocolReference)

    return dependency! as! T
  }
}

      

Using:

let object: Protocol = DependencyManager.inject(Protocol.self)

      

0


source







All Articles