将泛型 AnyObject 向下转换为协议关联类型 Self.Model

Downcast Generic AnyObject to Protocol Associated Type Self.Model

我正在开发一个库 Restofire,我想在其中保留一个配置对象。我想在配置对象中有一个 ResponseSerializer,但问题是 ResponseSerializer 是一个通用的。

public struct Configuration<M> {

    /// The Default `Configuration`. 
    static let defaultConfiguration = Configuration<AnyObject>()

    /// The base URL. `nil` by default.
    public var baseURL: String!

    /// The `ResponseSerializer`
    public var responseSerializer: ResponseSerializer<M, NSError> = AlamofireUtils.JSONResponseSerializer()

    /// The logging, if enabled prints the debug textual representation of the 
    /// request when the response is recieved. `false` by default.
    public var logging: Bool = false

}

我使用 baseUrl 设置了默认配置 Configuration.defaultConfiguration.baseUrl = "http://httpbin.org/"

我有一个带有 associatedType 要求的协议,它使用 defaultConfiguration 作为默认实现。但是我需要将通用 AnyObject 更改为关联类型模型,以便配置对象的 responseSerializer returns 类型模型。

public protocol Configurable {

    associatedtype Model

    /// The Restofire configuration.
    var configuration: Configuration<Model> { get }

}

public extension Configurable {

    /// `Restofire.defaultConfiguration`
    // Cannot convert return expression of Configuration<AnyObject> to return type Configuration <Self.Model>
    public var configuration: Configuration<Model> {
        return Restofire.defaultConfiguration
    }

}

我收到错误 Cannot convert return expression of Configuration<AnyObject> to return type Configuration <Self.Model>

我如何向下转换以使用 Model 而不是 AnyObject?

我还有一个继承自 Configurable 的 Requestable 协议

public protocol Requestable: Configurable {

    /// The type of object returned in response.
    associatedtype Model

    /// The base URL.
    var baseURL: String { get }

    /// The path relative to base URL.
    var path: String { get }

    /// The request parameters.
    var parameters: AnyObject? { get }

    /// The logging.
    var logging: Bool { get }

    /// The Response Serializer
    var responseSerializer: ResponseSerializer<Model, NSError> { get  }
}

// MARK: - Default Implementation
public extension Requestable {

    /// `configuration.BaseURL`
    public var baseURL: String {
        return configuration.baseURL
    }

    /// `nil`
    public var parameters: AnyObject? {
        return nil
    }

    /// `configuration.logging`
    public var logging: Bool {
        return configuration.logging
    }

    /// `configuration.responseSerializer`
    var responseSerializer: ResponseSerializer<Model, NSError> {
         return configuration.responseSerializer
    } 

}

RealCode 在 https://github.com/Restofire/Restofire/compare/Add/DefaultResponseSerializer

我可以直接在下面做,但用户将无法使用配置对象进行设置。

// MARK: - Default Implementation
public extension Requestable {

    /// `configuration.responseSerializer`
    var responseSerializer: ResponseSerializer<Model, NSError> {
         return AlamofireUtils.JSONResponseSerializer()
    } 

}

还有其他方法吗?

你想做的事是不可能的。这是因为 Swift.

中的强类型安全系统

您似乎想将 configuration 限制为关联类型 Model,但您还想提供默认配置。这里的问题是您的默认配置无法保证其泛型类型与 Model 的类型相同。

Swift 类型系统不允许您将 <AnyObject> 作为类型 <Model> 传递,因为它无法确保对象实际上是 Model类型。

当你使某些东西符合 Configurable 并声明 Model 的类型时,你是在说,"My configuration must use the type I've given." defaultConfiguration 不能保证这一点,所以不能这样使用。

通过查看您的代码,您正在使用它来确定要使用的 responseSerializer 的类型。但是,如果您使用不同的 Configurable 对象,它们都需要不同的 responseSerializer,因此它们不能都使用默认配置。

我花了很多时间思考这个问题,但我没有找到任何解决办法。您将不得不以某种方式更改您的设计。

如果将 responseSerializer 移至 Configurable 协议,则可以使 Configuration 非通用。在这种情况下,您将能够在 Configurable 上的协议扩展中创建 responseSerializer。如果您需要将 responseSerializer 与独立于 Configurable 对象的配置一起使用,那么无论您在哪里使用它,都必须创建一个 responseSerializer<AnyObject, NSError>。我不熟悉您图书馆的整个设计和意图,所以我不确定这是否适用于您想要实现的目标。

我可以肯定地告诉您的一件事是,您的设计必须更改才能使用 defaultConfiguration