Using Generics in Handler Completion

I have a simple application that communicates with a server via TCP Socket using its own protocol. I want to get an HTTP-like request response abstracting from the socket level. So I have a simple protocol:

protocol ResponseType {
   init(with frame: SocketMessage)
}

And some examples:

struct MessageAck: ResponseType {
  var messageId: String
  init(with frame: SocketMessage) {
    messageId = frame.messageId
  }
}

I created a simple protocol for sending requests:

protocol APIClient {
  func send<T: ResponseType>(request: SocketAPIRequest, completion:  ((Result<T>) -> Void)?)
}

enum SocketAPIRequest {
   case textMessage(messageId: String, ...)
   ...
}

And finally:

enum Result<T> {
  case success(T)
  case failure(Error)
}

class SocketAPIClient: APIClient {
  typealias MessageId = String
  private var callbacks = [Receipt: ((Result<ResponseType>) -> Void)]()

  ...

  func send<T>(request: SocketAPIRequest, completion: ((Result<T>) -> Void)?) where T : ResponseType {
    ....
    callbacks[stompFrame.receiptId] = completion
    ....
  }
}

So, when I want to save a callback for each request, to call it after receiving a response, I got this error:

Cannot assign value of type '((Result<T>) -> Void)?' to type '((Result<ResponseType>) -> Void)?'

I think the problem is with mixing type and objects, or maybe with something else.

+4
source share
2 answers

Swift generics ( , ). , Result<Apple> Result<Fruit>. Swift Generics Upcasting.

, Result<MessageBody> , a Result<MessageAck>? :

for callback in callbacks {
    callback(result)
}

, result?

( ):

, , . :

class SocketAPIClient: APIClient {
    typealias MessageId = String
    private var callbacks = [Receipt: ((Result<SocketMessage>) -> Void)]() // <--- Change

    func send<T>(request: SocketAPIRequest, completion: ((Result<T>) -> Void)?) where T : ResponseType {

        // Store the closure we don't understand inside a closure we do
        callbacks[stompFrame.receiptId] = { result in
            switch result {
            case .success(let message):
                completion?(.success(T.init(with: message)))
            case .failure(let error):
                completion?(.failure(error))
            }
        }
    }
}

, T callbacks, , , T . , callback , Result<SocketMessage>, , , .


:

, Result<Data> T:

protocol APIClient {
    func send(request: SocketAPIRequest, completion: ((Result<Data>) -> Void)?)
}

MessageAck ( ) .

, , .

+2

func send<T:ResponseType>(request: SocketAPIRequest, completion: ((Result<T>) -> Void)?){ ... }

?

1: , , -

protocol APIClient {
  associatedtype T
  func send(request: SocketAPIRequest, completion:  ((Result<T>) -> Void)?)
}

class SocketAPIClient: APIClient {
  typealias MessageId = String
  typealias T = ResponseType
  private var callbacks = [Receipt: ((Result<ResponseType>) -> Void)]()

  ...

  func send(request: SocketAPIRequest, completion: ((Result<T>) -> Void)?) {
    ....
    callbacks[stompFrame.receiptId] = completion
    ....
  }
}
0

Source: https://habr.com/ru/post/1695865/


All Articles