christopher.online
christopher.online

Reputation: 2774

How do I implement a Swift protocol with a generic constrained type property?

I would like to have a protocol that looks something like this:

protocol ReturnType {
    var returnType: ImmutableMappable.Type { get }
}

The part of the enum implementing the protocol:

extension ShimEndPoint: ReturnType {
    var returnType: ImmutableMappable.Type {
        switch self {
        case .deAuthorize(_, _):
            return EmptyResponse.self
        case .authorize(_, _):
            return AuthorizeResponse.self
        case .step(_, _, _, _):
            return StepResponse.self 
        }
    }
}

EmptyResponse, AuthorizeResponse and StepResponse all implement ImmutableMappable. Now I would like to use the "returnType" property in a function call:

return Shim.provider
    .request(endPoint)
    .timeout(7,
             scheduler: MainScheduler.asyncInstance)
    .retry(3)
    .mapObject(endPoint.returnType)

The line mapObject gives me the following compiler error: "Cannot convert value of type 'ImmutableMappable.Type' to expected argument type 'T.Type'

The function signature of "mapObject" is:

public func mapObject<T : ImmutableMappable>(_ type: T.Type) -> RxSwift.Observable<T>

How do I define and implement the protocol so I can pass in my returnType to the mapObject function?

I found a similar question but unfortunately I could not solve my problem with the help of the answer given: Returning constrained generics from functions and methods

Upvotes: 4

Views: 811

Answers (1)

Personally, I feel like some of your code just doesn't really make sense. Like :

extension ShimEndPoint: ReturnType {
    var returnType: ImmutableMappable.Type {
        switch self {
        case .deAuthorize(_, _):
            return EmptyResponse.self
        case .authorize(_, _):
            return AuthorizeResponse.self
        case .step(_, _, _, _):
            return StepResponse.self 
        }
    }
}

How can an object determined the type of itself based on itself ? And then return a value type different than itself ?

So what I'm trying to help here is just trying to find a solution of what you are trying to achieve, rather than solve the existing code.

I assume that what you trying to do is determined a type of object to map to depends on the result case at runtime. The enum itself is ImmutableMappable and it has 3 cases : .authorize, .deauthorize and .step.

The function .request will return this type and determined the type to map to, accordingly to the case. However, since the type of object need to be determined at compile time, all the result type EmptyResponse, AuthorizeResponse and StepResponse here must be following a same protocol ( I assume, Response here) and the result will also only return the protocol rather a specific class type.

return Shim.provider
    .request(endPoint)
    .timeout(7,
             scheduler: MainScheduler.asyncInstance)
    .retry(3)
    .flatMap { result: ImmutableMappable -> Observable<Response> in
       return Observable.create{
        switch result {
          case .authorize:
            observer.onNext(AuthorizeResponse())
          case .deAuthorize:
            //etc
          case step:
            //etc.
           }
        }
     }

Hope this answer your question !

Upvotes: 1

Related Questions