0

是否可以在泛型中使用泛型?

我有这个协议

public protocol ListViewModelProtocol {
    typealias ViewModel
    typealias Cell

    func titleForHeaderInSection(section: Int) -> String?
    func numberOfSections() -> Int
    func numberOfRowsInSection(section: Int) -> Int
    func viewModelAtIndexPath(indexPath: NSIndexPath) -> ViewModel
}

我也有ListViewModel实现这个协议的基础

public class BaseListViewModel<T, U> : ListViewModelProtocol  {
}

但是已经在这里它说我ListViewModelProtocol的没有实现。如何将 T 和 U 设置为协议内的特定类?因为如果我在协议中写这个

typealias ViewModel: CustomClass
typealias Cell: CustomCell

它仍然无法正常工作。

我的目标是子BaseListViewModel类化

public class TestListViewModel : BaseListViewModel<TestCellViewModel, TestTableViewCell> { 
}

然后我可以在我的BaseViewController

public class BaseViewController<T: ListViewModelProtocol>: UITableViewController  {
}

在一些子类ViewController中这样做:

public class CustomViewController: BaseViewController<TestListViewModel>  {
}

这样CustomViewController会“得到”TestCellViewModelTestTableViewCell(实际上是它的 BaseViewController)。

但是,这当然不像我预期的那样工作。我错过了什么?或者我必须在每个实现它或将它用作泛型类型的类中typealias定义?ListViewModelProtocol这意味着我必须在类和类中定义ViewModeland Cellof ,但这不是那么通用,因为我只想将它们的基类型放在协议中,仅此而已。ListViewModelProtocolBaseListViewModelBaseViewController

或者也许我的方法有问题,我应该以不同的方式实施?

任何建议都是有用的。谢谢

编辑

我已经设法解决了这个问题,但我还有另一个问题。

    public class BaseViewController<T: ListViewModelProtocol>: UITableViewController  {
         var dataSource: T?
    }

这个数据源通过调用它自己的方法在 UITableViewDataSource 方法中使用(参见 ListViewModelProtocol 方法)。一切正常,但是当一些自定义控制器:

Controller: BaseViewController<TestListViewModel>

正在取消初始化我收到 EXC_BAD_ACCESS 错误。如果我把

deinit {
    self.dataSource = nil
}

它有效,但我想知道为什么我需要将其设置为零。

谢谢。

4

2 回答 2

1

typealias 关键字有不止一个含义...

// protocol can't be generic
protocol P {
    // here typealias is just placeholder, alias
    // for some unknown type
    typealias A
    func foo(a:A)->String
}

// C is generic
class C<T>:P {
    // here typealias define the associated type
    // in this example it is some generic type
    typealias A = T
    func foo(a: A) -> String {
        return String(a)
    }
}

let c1 = C<Int>()
print(c1.foo(1))     // 1

let c2 = C<Double>()
print(c2.foo(1))     // 1.0

// D is not generic!!!
class D: C<Double> {}

let d = D()
print(d.foo(1)) // 1.0

更新,回答讨论中的问题

class Dummy {}

protocol P {
    // here typealias is just placeholder, alias
    // for some inknown type
    typealias A : Dummy
    func foo(a:A)->String
}

// C is generic
class C<T where T:Dummy>:P {
    // here typealias define the associated type
    // in this example it is some generic type
    typealias SomeType = T
    func foo(a: SomeType) -> String {
        return String(a)
    }
}

class D:Dummy {}
let c = C<D>()
print(c.foo(D())) // D

// now next line doesn't compile
let c1 = C<Int>() // error: 'C' requires that 'Int' inherit from 'Dummy'
于 2016-01-18T17:01:57.343 回答
0

如果要实现具有关联类型的协议,则必须在通用实现中设置这些关联类型:

public class BaseListViewModel<T, U> : ListViewModelProtocol  {
  typealias ViewModel = T
  typealias Cell = U

  // implement the methods as well
}
于 2016-01-18T17:03:38.460 回答