如何在Swift中传递一个预期超协议类型的子协议类型? (认为​​传递子类类型为基类类型,但对于协议)

时间:2017-01-03 01:22:49

标签: swift inheritance swift-protocols protocol-inheritance

我遇到了Swift中的协议继承问题。我正在尝试构建一个接受协议类型X数组的API。此API的消费者应该能够传入任何类型的协议类型X或从协议X继承的任何子协议类型X'。这似乎可以 - 如果没有某种形式将协议类型X'显式地转换回协议类型X,则无法在Swift中实现。为什么会出现这种情况?我没有看到类型的这种行为(我怀疑它可能是因为继承的工作方式明显不同)。

这是我的代码:

public protocol InjectableService
{}

public protocol ClientDependency
{
    func serviceDependencies() -> [InjectableService.Type]
    func injectDependencies(dependencies: [InjectableService])
}



public protocol TouchIdServiceInterface : InjectableService
{
    func biometricAuthenticate() -> Void
}

public protocol PasswordServiceInterface : InjectableService
{
    func passwordAuthenticate() -> Void
}

public class LoginController : ClientDependency
{
    private var services: [InjectableService]!

    public func injectDependencies(dependencies: [InjectableService]) {
        services = dependencies
    }

    public func serviceDependencies() -> [InjectableService.Type] {
        return [TouchIdServiceInterface.self as! InjectableService.Type , PasswordServiceInterface.self as! InjectableService.Type]
    }


}

正如您在上面的函数serviceDependencies()中所看到的,我必须将子协议类型奇怪地转换回其超级协议类型。如果我删除了演员,我会明确地要求我做一个编译器警告。

有什么方法可以避免这种情况吗?我喜欢它的类型,它可以为你解决。我真的想避免这个转换问题,因为它会使API非常笨重。谢谢!

1 个答案:

答案 0 :(得分:0)

来自Apple文档:

  

元数据类型

     

元类型类型是指任何类型的类型,包括类类型,   结构类型,枚举类型和协议类型。

     

类,结构或枚举类型的元类型是其名称   该类型后跟.Type。协议类型的元类型 - 不是   在运行时符合协议的具体类型是名称   该协议后跟.Protocol。例如,元的类型   类类型SomeClass是SomeClass.Type和元类型   协议SomeProtocol是SomeProtocol.Protocol

     

您可以使用postfix self表达式将类型作为值进行访问。   例如,SomeClass.self返回SomeClass本身,而不是实例   SomeClass。并且SomeProtocol.self返回SomeProtocol本身,而不是   一个在运行时符合SomeProtocol的类型的实例。

如果要返回[InjectableService.Type],则需要定义每个协议的类。

public protocol InjectableService
{}

public protocol ClientDependency
{
    func injectDependencies(dependencies: [InjectableService])
    func serviceDependencies() -> [InjectableService.Type]
}

public protocol TouchIdServiceInterface : InjectableService
{
    func biometricAuthenticate() -> Void
}

public protocol PasswordServiceInterface : InjectableService
{
    func passwordAuthenticate() -> Void
}

public class TouchIdService: TouchIdServiceInterface {
    public func biometricAuthenticate() -> Void { }
}

public class PasswordService: PasswordServiceInterface {
    public func passwordAuthenticate() -> Void { }
}


public class LoginController: ClientDependency
{
    private var services: [InjectableService]!

    public func injectDependencies(dependencies: [InjectableService]) {
        services = dependencies
    }

    public func serviceDependencies() -> [InjectableService.Type] {
        let ts: [InjectableService.Type] = [
            TouchIdService.self,
            PasswordService.self
        ]
        return ts
    }

}

let controller = LoginController()
let services = controller.serviceDependencies()

<强>已更新

public protocol ClientDependency
{
    func injectDependencies(dependencies: [InjectableService])
    func serviceDependencies() -> [Any]
}

的LoginController:

public func serviceDependencies() -> [Any] {
    let ts: [Any] = [
        TouchIdServiceInterface.self,
        TouchIdServiceInterface.self
    ]
    return ts
}

测试:

let controller = LoginController()
let services = controller.serviceDependencies()
if let touchIdService = services.first as? TouchIdServiceInterface.Protocol {
    print(touchIdService)
}