如何定义一个Swift协议来强制其采用者自己符合相关类型?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何定义一个Swift协议来强制其采用者自己符合相关类型?相关的知识,希望对你有一定的参考价值。

我需要使用不仅符合协议的对象,还要公开它们符合的第二个协议的类型。 (这适用于NSXPCConnection,您必须在其中配置不仅要代理的对象,还要告诉它应该在该代理对象上公开哪个协议。)

我尝试过类似的东西:

protocol Conformer where Self : Conformer.P  {
    associatedtype P : Protocol
    static var interface : P {get}
    init(info: String)
}

func exposeOverXPC<T:Conformer>(_ _: T.Type) {
    let c : NSXPCConnection = …

    c.exportedInterface = NSXPCInterface(with: T.interface)
    c.exportedObject = T(info:"foo")
}

但它会导致错误:

关联类型“P”只能与具体类型或通用参数库一起使用

具体来说,我希望exposeOverXPC只接受以下对象:

  1. 可以以特定方式初始化
  2. 有一个引用协议的静态属性interface
  3. 他们自己是否符合所说的interface

这是我陷入困境的最后一步,有什么方法可以实现它吗?

答案

你不能限制谁符合协议,如果你考虑它,那就违背了协议的概念。但是,您可以在exposeOverXPC中的通用参数中使用组合类型Swift4功能。

protocol Interface {
}

protocol XPCExposable {
    associatedtype P: Interface

    init(info: String)
    static var interface: P { get }
}

func exposeOverXPC<T: XPCExposable & Interface>(_ : T.Type) {
    // 1: T is initializeable in a particular way
    // 2: Has a static property interface which references a protocol
    // 3: Are themselves conformant to said interface
}

是的,这限制T符合Interface而不是P,你最好的选择是使exposeOverXPC私人/内部并提供APIs期望Interface亚型。无论你有权访问Interface子类型,都会暴露那个api。例如:

解决方案1

protocol InterfaceSubType: Interface {
    fun test()
}

/// Create as many `API`s as the number of `Interface` subtypes you have.
func exposeOverXPC<T: XPCExposable & InterfaceSubType>(_ : T.Type) {
    exposeOverXPC(T.self)
}

/// set to private, you only want to expose the APIs with `Interface` subtype.
private func exposeOverXPC<T: XPCExposable & Interface>(_ : T.Type) {
    // Impl.
}

解决方案2

具有类型为关联类型的参数的函数的替代解决方案是通过扩展协议来添加该api(如果您希望的话,作为静态函数)。您必须知道此扩展中所有预期的Interface子类型。

extension XPCExposable {

    static func exposeOverXPC<T>(_ interface: P, _ xpcType: T.Type) where T: XPCExposable {

        // Expected subtype Interface 
        if let subInterface = interface as? InterfaceSubType {
            subInterface.test()
        }

        // Other subtypes here.
    }
}

可以称为:

let impl = Impl(info: "")
Impl.exposeOverXPC(Impl.interface, Impl.self)

它是XPCExposable的扩展,所以你将调用者限制为一个conformer,参数需要XPCExposable.P所以你已经设置好了。该解决方案的缺点是:

  1. 您有两个参数而不是一个。
  2. 它使用qazxsw poi条件,我不知道这是否值得一提,除了我想推出第一个解决方案作为最爱。

以上是关于如何定义一个Swift协议来强制其采用者自己符合相关类型?的主要内容,如果未能解决你的问题,请参考以下文章

如何创建符合 Swift 和 Objective-C 之间共享协议的类方法?

来自符合协议的未知类的 Swift init

符合自定义协议的通用函数 - Swift

无法将符合协议的 Objective-C 类分配给具有 Swift 协议的属性

如何判断一个 Swift 类是继承自另一个类还是符合协议?

Swift:检查泛型类型是不是符合协议