Kyle Begeman Kyle Begeman - 1 year ago 157
iOS Question

Writing API requests with completion blocks using Swift generics

I am experimenting with generics in Swift and I am attempting to push it to its limits.

In my application I have a super simple API wrapper around Alamofire. The structure is like so:

API -> Request -> Alamofire request

For the sake of example, lets say I have a Vehicle base class, and I am fetching cars, trucks, and boats. Car has its own subclass of Vehicle, same for Truck and Boat.

Each item is passed up the chain using typealiased completion like so:

typealias CarsRequestCompletion = ([Car]?, NSError?) -> Void

As you can imagine, I have a typealias for each Vehicle subclass, as well as a Request object for each subclass. In the future the number of subclasses vehicles and requests will increase greatly.

Here is an example of the existing methods (combined for ease of reading):

typealias CarRequestCompletion = ([Car]?, NSError?) -> Void

func requestCarsWithCompletion(completion: CarRequestCompletion) {

func performRequestWithCompletion(completion: CarRequestCompletion) {
// Some Alamofire fetching and object mapping
completion(mappedCar, error)


API().requestCarsWithCompletion() { cars, error in
if (error) {
// Do something
} = cars!

Keep in mind the above examples are just pseudocode. Repeating this becomes cumbersome and time consuming. This is where generics come in, but I am running into some interesting issues.

As far as I can tell, Swift 2.2 does not support generic typealiased properties. Here is an example workaround I have found but not tested:


Frankly, the type alias is not a requirement at all. Here is an example I have tried with a inline completion definition and it does not seem to work:

func requestCarsWithCompletion<T: BaseRequest, U: Vehicle>(completion: ([U]?, NSError) -> Void) {

Any insight into how I might accomplish this would be great, thanks!


Here is some generic code that I through into a playground to test some concepts. Here is what I have so far (note that I have omitted the type alias completion as it is not important and just adds unnecessary complexity):

protocol AnotherProtocol {
var cheese: String { get }

class Something: AnotherProtocol {
required init() { }

var cheese: String {
return "wiz"

class API {

class func performRequest<T: AnotherProtocol>(completion: (T?, NSError) -> Void) {

// This code is irrelevant, just satisfying the completion param
let test = T()
let error = NSError(domain: "Pizza", code: 1, userInfo: nil)

completion(test, error)


func test() {
API.performRequest<Something> { item, error in


Calling the function gives the error:

"Cannot explicitly specialize a generic function"

Answer Source

The way generics work is they allow a function to use unspecialized variables inside of its implementation. One can add functionality to these variables by specifying that the variables must conform to a given protocol (this is done within the declaration). The result is a function that can be used as a template for many types. However, when the function is called in the code itself, the compiler must be able to specialize and apply types to the generics.

In your code above, try replacing

func test() {
    API.performRequest<Something> { item, error in



func test() {
    API.performRequest { (item: Something?, error) in


this lets the compiler know which type it must apply to the function without explicitly specifying. The error message you received should now make more sense.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download