Wieczorny
Wieczorny

Reputation: 181

Generic delegate in Swift

I'm writing a small class which helps to fetch paged data automatically.

I have following delegate:

protocol DataAPIDelegate: class {
  func fetchItemsForPage<T>(api: DataAPI<T>, page: Int, onFinish: ([T] -> ())
}

And DataAPI class, which stores delegate:

class DataAPI<T> {
  weak var delegate: DataAPIDelegate? = nil

  //...
  //some other methods
}

Then, what I want to do is to write a view controller which uses DataAPI and communicates with this object by DataAPIDelegate:

class CarsViewController: DataAPIDelegate {
  var dataAPI = DataAPI<Car>

  // MARK :- DataAPIDelegate
  func fetchItemsForPage<T>(api: DataAPI<T>, page: Int, onFinish: ([T] -> ()) {
    let cars: [Car] = //some method for getting cars
    onFinish(cars)
  }
}

And I get the error: Cannot invoke 'onFinish' with an argument list of type '([Car])' in the line: onFinish(cars).

I think about it for a few hours and I don't have any idea why it doesn't work. Anyone meets that problem?

Upvotes: 2

Views: 1155

Answers (2)

Artyom Razinov
Artyom Razinov

Reputation: 301

Generic delegates aren't possible in Swift, if they aren't just functions. Because functions (closures) can be generic. See my gist where I tried to resolve the same problem: https://gist.github.com/artyom-razinov/fe8c2b7611a0ba3bd2a3

Upvotes: 0

0x416e746f6e
0x416e746f6e

Reputation: 10136

Generic functions provide single template implementation for multiple types referred by T, while what it seems you are trying to do is to provide an implementation of fetchItemsForPage method specifically for Car type.

The way it would work is:

protocol DataAPIDelegate: class {
    func fetchItemsForPage<T>(api: DataAPI<T>, page: Int, onFinish: ([T] -> ()))
}

class DataAPI<T> {
    weak var delegate: DataAPIDelegate? = nil

    //...
    //some other methods
}

struct Car { }

class CarsViewController: DataAPIDelegate {
    var dataAPI = DataAPI<Car>()

    // MARK :- DataAPIDelegate
    func fetchItemsForPage<T>(api: DataAPI<T>, page: Int, onFinish: ([T] -> ())) {
        let items: [T] = [T]()
        onFinish(items)
    }
}

... while what you are trying to do is:

struct Bike { }

class BikesViewController: DataAPIDelegate {
    var dataAPI = DataAPI<Bike>()

    // MARK :- DataAPIDelegate
    func fetchItemsForPage<Bike>(api: DataAPI<Bike>, page: Int, onFinish: ([Bike] -> ())) {
        let items: [Bike] = [Bike]()
        onFinish(items)
    }
}

... but in the latter snippet Bike is not a type but a placeholder, which works just the same as if you would use T.

Upvotes: 1

Related Questions