swift - 如何定义一个 Swift 协议(protocol),强制其采用者自己遵守相关类型?

标签 swift generics swift-protocols

我需要处理的对象不仅要符合协议(protocol),还要公开它们所遵循的第二个 协议(protocol)的类型。 (这是为了与 NSXPCConnection 一起使用,您不仅必须配置要代理的对象,还要告诉它应在该代理对象上公开哪个协议(protocol)。)

我试过类似的方法:

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

但它会导致错误:

Associated type 'P' can only be used with a concrete type or generic parameter base

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

  1. 可以以特定方式初始化
  2. 有一个引用协议(protocol)的静态属性interface
  3. 本身符合所述接口(interface)

这是我卡住的最后一步,有什么办法可以完成吗?

最佳答案

您不能限制谁遵守协议(protocol),如果您考虑一下,这首先违背了拥有协议(protocol)的概念。但是,您可以在 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 private/internal 并提供需要 Interface 子类型的 API。无论您在哪里可以访问 Interface 子类型,都可以公开该 api。例如:

解决方案一

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

方案二

另一种解决方案是通过扩展协议(protocol)来添加该 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 的扩展,因此您可以将调用者限制为符合者,并且参数需要 XPCExposable.P,因此一切就绪。 此解决方案的缺点是:

  1. 你有两个参数而不是一个。
  2. 它使用 if 条件,我不知道这是否值得一提作为缺点,除了我想将第一个解决方案推为最喜欢的。

关于swift - 如何定义一个 Swift 协议(protocol),强制其采用者自己遵守相关类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49057938/

相关文章:

ios - 将数据从 Pop-over ViewController UITextfield 传回 Master ViewController

c# - 如何在 C# 中为测量单位创建通用转换器?

java - 尝试反射(reflect)接受泛型类型的方法

swift - UIViewController 的 self 约束协议(protocol)扩展

ios - 如何隐藏我的 UITableViewCell 之外的内容

javascript - 使用云代码 Swift 保存到 PFUser

ios - FIRDataBaseReference 未被识别

java - 使用类型变量泛型调用方法

json - 如何使用 Codable 类型定义变量?

swift - 我什么时候以及为什么要在 Swift 中使用协议(protocol)?