Tengo un protocolo de RequestType y ha associatedType Modelo como el siguiente.

public protocol RequestType: class {

    associatedtype Model
    var path: String { get set }

}

public extension RequestType {

    public func executeRequest(completionHandler: Result<Model, NSError> -> Void) {
        request.response(rootKeyPath: rootKeyPath) { [weak self] (response: Response<Model, NSError>) -> Void in
            completionHandler(response.result)
            guard let weakSelf = self else { return }
            if weakSelf.logging { debugPrint(response) }
        }
    }

}

Ahora estoy tratando de hacer una cola de todas las solicitudes con error.

public class RequestEventuallyQueue {

    static let requestEventuallyQueue = RequestEventuallyQueue()
    let queue = [RequestType]()

}

Pero me sale el error en la línea let queue = [RequestType]() que el Protocolo de RequestType sólo puede ser utilizado como una restricción genérica porque tiene Auto o associatedType requisitos.

2 Comentarios

  1. 109

    Supongamos por el momento que ajustar su protocolo para agregar una rutina que utiliza el tipo asociado:

     public protocol RequestType: class {
         associatedtype Model
         var path: String { get set }
    
         func frobulateModel(aModel: Model)
     }

    Y Swift fueron a dejar de crear una matriz de RequestType de la manera que usted desea. Me podría pasar una matriz de los tipos de peticiones en una función:

    func handleQueueOfRequests(queue: [RequestType]) {
        //frobulate All The Things!
    
        for request in queue {
           request.frobulateModel(/* What do I put here? */)
        }
    }

    Me pongo hasta el punto de que quiero frobulate todas las cosas, pero necesito saber qué tipo de argumento para pasar a la llamada. Algunos de mis RequestType entidades podrían tomar un LegoModel, algunos podrían tomar un PlasticModel, y otros podrían tomar un PeanutButterAndPeepsModel. Swift no es feliz con la ambigüedad, así que no vamos a declarar una variable de un protocolo que tiene un tipo asociado.

    Al mismo tiempo lo hace perfecto sentido, por ejemplo, crear una matriz de RequestType cuando SABEMOS que todos ellos utilizan el LegoModel. Esto parece razonable, y lo es, pero se necesita alguna manera de expresarlo.

    Una manera de hacer esto es crear una clase (o la estructura, o enumeración) que se asocia un tipo real con el Modelo abstracto de nombre de tipo:

    class LegoRequestType: RequestType {
      typealias Model = LegoModel
    
      //Implement protocol requirements here
    }

    Ahora es totalmente razonable para declarar una matriz de LegoRequestType porque si queríamos frobulate todos ellos sabemos que tendríamos que pasar en un LegoModel cada vez.

    Este matiz con Tipos hace que cualquier protocolo que usa especiales. El Swift de la Biblioteca Estándar dispone de Protocolos como este, el más notablemente Collection o Sequence.

    Para permitir que usted para crear un conjunto de cosas que implementan la Collection protocolo o un conjunto de cosas que implementar la secuencia de protocolo, la Biblioteca Estándar se emplea una técnica llamada «tipo de borrado» para crear la estructura de los tipos de AnyCollection<T> o AnySequence<T>. El tipo de técnica de borrado es bastante complejo de explicar en un Desbordamiento de Pila respuesta, pero si usted busca en la web hay un montón de artículos sobre ella.

    Me puede recomendar un vídeo de Alex Gallagher en los Protocolos Asociados a los Tipos (PATs) en YouTube.

    • «la solución es muy genérico» 😂
    • Esta es una de las mejores explicaciones que he visto de este problema
    • Así que BUENA explicación, así que la única respuesta.
  2. 0

    Un pequeño cambio en el diseño de su código podría hacer posible. Añadir un vacío, no associatedType, protocolo en la parte superior de su protocolo de jerarquía. Como esto…

    public protocol RequestTypeBase: class{}
    
    public protocol RequestType: RequestTypeBase {
    
        associatedtype Model
        var path: Model? { get set } //Make it type of Model
    
    }
    public class RequestEventuallyQueue {
    
        static let requestEventuallyQueue = RequestEventuallyQueue()
        var queue = [RequestTypeBase]() //This has to be 'var' not 'let'
    
    }

    Otro ejemplo, con las clases que derivan del protocolo de RequestType, haciendo una cola y pasar la cola de una función para imprimir tipo adecuado

    public class RequestA<AType>: RequestType{
       public typealias Model = AType
       public var path: AType?
    }
    public class RequestB<BType>: RequestType{
       public typealias Model = BType
       public var path: BType?
    }
    
    var queue = [RequestTypeBase]()
    
    let aRequest: RequestA = RequestA<String>()
    aRequest.path = "xyz://pathA"
    
    queue.append(aRequest)
    
    let bRequest: RequestB = RequestB<String>()
    bRequest.path = "xyz://pathB"
    
    queue.append(bRequest)
    
    let bURLRequest: RequestB = RequestB<URL>()
    bURLRequest.path = URL(string: "xyz://bURLPath")
    
    queue.append(bURLRequest)
    
    func showFailed(requests: [RequestTypeBase]){
    
        for request in requests{
            if let request = request as? RequestA<String>{
                print(request.path!)
            }else if let request = request as? RequestB<String>{
                print(request.path!)
            }else if let request = request as? RequestB<URL>{
                print(request.path!)
            }
    
        }
    }
    
    showFailed(requests: queue)

Dejar respuesta

Please enter your comment!
Please enter your name here