作者热门文章
- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我面临着使用泛型类和继承的问题。
问题简述:
我有一个名为 BookPageDataSource
的基类和两个具有不同实现的继承类( ReadingBookPageDataSource
和 StarsBookPageDataSource
)。
另外,我有一个通用类 BookPageViewController
包含此数据源的通用参数和从此类继承的两个类( ReadingBookPageViewController
和 StarsBookPageViewController
)。
我需要写一个方法,它的返回参数是BookPageViewController<DataSource>
.
// Data Sources
class BookPageDataSource { }
class ReadingBookPageDataSource: BookPageDataSource { }
class StarsBookPageDataSource: BookPageDataSource { }
// Controllers
class BookPageViewController<DataSource: BookPageDataSource>: UIViewController {
let dataSource: DataSource
init(dataSource: DataSource) {
self.dataSource = dataSource
super.init(nibName: nil, bundle: nil)
}
required init?(coder aDecoder: NSCoder) {
return nil
}
}
final class ReadingBookPageViewController: BookPageViewController<ReadingBookPageDataSource> { }
final class StarsBookPageViewController: BookPageViewController<StarsBookPageDataSource> { }
// Communication
class Pager {
func currentPageController<DataSource>(at index: Int) -> BookPageViewController<DataSource> {
// for example
if index == 0 {
// How to remove the cast from the line below?
return readingPageController() as! BookPageViewController<DataSource>
}
return starsPageController() as! BookPageViewController<DataSource>
}
private func readingPageController() -> ReadingBookPageViewController {
return ReadingBookPageViewController(dataSource: ReadingBookPageDataSource())
}
private func starsPageController() -> StarsBookPageViewController {
return StarsBookPageViewController(dataSource: StarsBookPageDataSource())
}
}
currentPageController
总是崩溃,因为数据源总是等于
BookPageDataSource
, 不至
ReadingBookPageDataSource
或
StarsBookPageDataSource
.
最佳答案
概念讨论
您对架构的概念有缺陷,这导致了您的问题。
简单的泛型示例
这是一个非常简单的泛型函数示例,它只返回您给它的值:
func echo <T> (_ value: T) -> T { return value }
T
? Swift 是一种类型安全的语言,这意味着最终不允许有任何关于类型的歧义。那么为什么允许这种回声功能呢?答案是当我在某处实际使用这个函数时,类型的歧义将被消除。例如:
let myValue = echo(7) // myValue is now of type Int and has the value 7
Int
来消除歧义。 ,因此编译器对所涉及的类型没有不确定性。
func currentPageController <DataSource> (at index: Int) -> BookPageViewController<DataSource>
DataSource
在返回类型中,而不是在输入中 - 编译器应该如何弄清楚
DataSource
是?* 我想这就是你想象中使用你的函数的方式:
let pager = Pager()
let controller = pager.currentPageController(at: 0)
controller
的类型是什么? ?你能期望用它做什么?您似乎希望
controller
将根据您传入的值(
0
)采用正确的类型,但这不是它的工作方式。泛型参数是根据输入的类型确定的,而不是输入的值。你希望通过
0
将产生一种返回类型,而
1
将产生不同的结果 - 但在 Swift 中这是禁止的。两者
0
和
1
属于
Int
类型,而类型才是最重要的。
controller
为了。你真正需要的是什么?如果你只是想把它推到导航 Controller 上,那么你不需要它是一个
BookPageViewController
.你只需要它是一个
UIViewController
使用该功能,所以你的功能可以变成这样:
func currentPageController (at index: Int) -> UIViewController {
if index == 0 {
return readingPageController()
}
return starsPageController()
}
BookPageViewController
的功能。那么这取决于你想要做什么。如果
BookPageViewController
上有方法像这样:
func doSomething (input: Int) -> String
DataSource
那么您可能希望将该函数分离为它自己的非通用协议(protocol)/父类(super class)。例如:
protocol DoesSomething {
func doSomething (input: Int) -> String
}
BookPageViewController
符合它:
extension BookPageViewController: DoesSomething {
func doSomething (input: Int) -> String {
return "put your implementation here"
}
}
func currentPageController (at index: Int) -> DoesSomething {
if index == 0 {
return readingPageController()
}
return starsPageController()
}
let pager = Pager()
let controller = pager.currentPageController(at: 0)
let retrievedValue = controller.doSomething(input: 7)
UIViewController
无论如何,您可能要考虑重命名函数和相关变量。
DataSource
.一个基本的例子是:
extension BookPageViewController {
func setDataSource (_ newValue: DataSource) {
self.dataSource = newValue
}
}
BookPageViewController<DataSource>
.你做什么工作?好吧,如果您真正想要的是使用
setDataSource(_:)
上面定义的方法那么你必须有一个
DataSource
您打算作为参数传入的对象,对吗?如果是这种情况,那么我们正在取得进展。以前,您只有一些
Int
您传递给函数的值,问题是您无法用它指定通用返回类型。但是如果你已经有了
BookPageDataSource
值(value)那么至少在逻辑上您可以使用它来专门化您的
Int
无论
DataSource
是什么,都可以在该索引处获取 Controller 类型是。但如果你不在乎什么
DataSource
是返回的
BookPageViewController
那么你怎么能期望设置它的
DataSource
使用
setDataSource(_:)
到其他东西方法?
DataSource
(您只想要与您提供的索引相对应的任何一个)-您需要它具有完全相同的类型
DataSource
你打算在使用它时传入它,否则你给它的类型是错误的。
关于ios - Swift 泛型类、继承和协方差,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52111488/
我是一名优秀的程序员,十分优秀!