Skip to content

Instantly share code, notes, and snippets.

@khanlou
Created May 4, 2017 15:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save khanlou/bcb3589e78877c232058fa6646fbca6b to your computer and use it in GitHub Desktop.
Save khanlou/bcb3589e78877c232058fa6646fbca6b to your computer and use it in GitHub Desktop.
Protocols with associatedtypes
import Foundation
protocol JSONInitializable {
init?(data: Data)
}
protocol Request {
associatedtype OutputType: JSONInitializable
var url: URL { get }
}
class NetworkClient {
// Note that this function is generic over `RequestType`. This means that *at compile time*, it is known what RequestType (and therefore OutputType) will be. This is the crucial bit for making this technique work.
func send<RequestType>
(request: RequestType, // Here we use `RequestType` the new type that we defined for this function specifically, instead of the PAT `Request`
successBlock: @escaping (RequestType.OutputType) -> (), // The parameters can reference the types defined for this function.
failureBlock: @escaping (Error) -> ())
where RequestType: Request // Here, we're "constraining" `RequestType` to conform to `Request`. More complex contraints are also possible.
{
let urlRequest = URLRequest(url: request.url)
URLSession.shared.dataTask(with: urlRequest, completionHandler: { data, response, error in
if let error = error {
failureBlock(
} else if let data = data,
// We can freely refer to `RequestType.OutputType` here.
let output = RequestType.OutputType(data: data) {
successBlock(output)
}
}).resume()
}
}
import Foundation
protocol JSONInitializable {
init?(data: Data)
}
protocol Request {
associatedtype OutputType: JSONInitializable
var url: URL { get }
}
class NetworkClient {
func send(request: Request,
successBlock: @escaping (RequestType.OutputType) -> (), // Without the generic constraint, we have no way to refer to the OutputType of the *specific* Request that we're working with.
failureBlock: @escaping (Error) -> ()) {
let urlRequest = URLRequest(url: request.url)
URLSession.shared.dataTask(with: urlRequest, completionHandler: { data, response, error in
if let error = error {
failureBlock(
} else if let data = data,
// Same issue here. How can I specify that the OutputType I want is the one associated with the Request that I passed in?
let output = RequestType.OutputType(data: data) {
successBlock(output)
}
}).resume()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment