是否可以在通用内部使用泛型?
我有这个协议
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
会“获得”TestCellViewModel
和TestTableViewCell
(实际上是它的BaseViewController)。
但当然这不符合我的预期。我错过了什么?或者我必须在实现它的每个类中为typealias
定义ListViewModelProtocol
或将其用作泛型类型?这意味着我必须在ViewModel
类和Cell
类中定义ListViewModelProtocol
BaseListViewModel
BaseViewController
,但这不是那么通用,因为我只是想把它们的基本类型放在协议中就可以了。
或许我的方法可能有问题,我应该以不同的方式实现这一点?
任何建议都很有用。感谢
修改
我已设法解决这个问题,但我还有其他问题。
public class BaseViewController<T: ListViewModelProtocol>: UITableViewController {
var dataSource: T?
}
此数据源通过调用自己的方法在UITableViewDataSource方法中使用(请参阅ListViewModelProtocol方法)。一切正常,但是当一些自定义控制器:
Controller: BaseViewController<TestListViewModel>
正在取消初始化我收到EXC_BAD_ACCESS错误。如果我把
deinit {
self.dataSource = nil
}
它有效,但我想知道为什么我需要将它设置为零。
感谢。
答案 0 :(得分: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'
答案 1 :(得分:0)
如果要实现具有关联类型的协议,则必须在通用实现中设置这些关联类型:
public class BaseListViewModel<T, U> : ListViewModelProtocol {
typealias ViewModel = T
typealias Cell = U
// implement the methods as well
}