Swift metatype and ObjectiveC Protocol question

We have an ObjC API which receive a Protocol instance and return Any?.

// Imported ObjectiveC API
func resolve(_ p: Protocol) -> Any?

// Swift Side Code
@objc protocol P: NSObjectProtocol {
    func hello()
}

func test() {
    let p = resolve(P.self) as? P
    p?.hello()
}

In Swift side, we'd like to wrap the API to make it more swift-friendly.

func resolve2<T>(_ t: T.Type) -> T? {
    return resolve(t) as? T // ❌
    return resolve(t.self) as? T // ❌
    return resolve(T.self) as? T // ❌
    // ✅ Currently, I have to use the following code to make it compile
    // IMO, maybe I have to constraint T to be a protocol.
    // But I do not know how to express it in Swift
    guard let tt = NSProtocolFromString(NSStringFromClass(t.self)) else {
        return nil
    }
    return resolve(tt) as? T
}

// ✅ Or we must pass `P.self` twice on the caller side
func resolve3<T>(_ t: T.Type, _ t2: Protocol) -> T? {
    return resolve(t2) as? T
}

func test() {
    let p1 = resolve2(P.self)
    p1?.hello()

    let p2 = resolve3(P.self, P.self)
    p2?.hello()
}

Before the macro feature landed on Swift, how can I implement resolve2 properly without the dynamic NSXX call or pass P.self twice on the caller side?

Metatypes Background

Some background context about Swift's metatype :point_down:

/*
 https://swiftrocks.com/whats-type-and-self-swift-metatypes.html
    ```swift
    protocol P {}
    struct A: P {}
    ```
 
    Value       Type
    1           Int
    Int.self    Int.Type
    P.self      P.Protocol
    A.self      A.Type: (any P).Type
    P.self      Protocol // ?
 */

Or anyone can recommend some doc or material about The ObjectiveC Runtime Protocol'?
I can only find it out Protocol | Apple Developer Documentation here and know it looks like to be a class

I found this TODO in the swift compiler which may be relevant:

And this bug report, where Hatsune Miku tried to do the same thing and got nowhere:

1 Like

Is this API constructing a proxy object or something like that?

Swift doesn’t allow directly abstracting over protocols, so this is just not going to import well to Swift. Even in ObjC, it only really works because of ObjC’s very lax type conversions. I would guess that in practice it’s only used with a handful of protocols, though, and just copy-and-pasting a type-safe wrapper that returns a particular kind of proxy is probably the easiest thing to do.

I actually did find a way to do this:

(Source)

1 Like

It is working! Thanks

func resolve4<T: NSObjectProtocol>(_ t: T.Type) -> T? {
    guard let tt = T.self as Any.Type as AnyObject as? Protocol else {
        return nil
    }
    return resolve(tt) as? T
}

Is this API constructing a proxy object or something like that?

No. It is just some sort of "Dependency Injection frameworks" written in ObjC internally by someone in my team.

Some module component register to a context with a protocol conformance binding. And then later retrieve it through the context.

For some history reason, it can't be replaced with Swift. :cry: