[英]Swift Generics & Protocols
我正在尝试快速构建通用的类似于“ NSFetchResultsController”的协议集,以便可以将UITableViewDataSource/UICollectionViewDataSource
实现与任何有关在何处以及如何获取和更新数据的细节隔离开来。
因此,我首先对核心控制器及其部分进行了一些简单的定义:
import UIKit
import CoreData
public protocol ResultsSection {
typealias T
var numberOfObjects : Int { get }
var objects : [T] { get }
subscript(index: Int) -> T? { get }
}
public protocol ResultsController {
typealias ResultsSection
typealias T
var resultsSections : [ResultsSection] { get }
subscript(indexPath: NSIndexPath) -> T? { get }
}
在此之后的几个简单的实现仅将所有内容保存在数组中:
class SimpleResultsSection<T> : ResultsSection {
private(set) var objects : [T]
init(objects: [T]?) {
self.objects = objects ?? [T]()
}
var numberOfObjects : Int {
get {
return objects.count
}
}
subscript(index: Int) -> T? {
return objects.count > index ? objects[index] : nil
}
}
class SimpleResultsController<T, RS: ResultsSection where T == RS.T> : ResultsController {
internal(set) var resultsSections = [RS]()
subscript(indexPath: NSIndexPath) -> T? {
if resultsSections.count > indexPath.section {
let section = resultsSections[indexPath.section]
return section[indexPath.row]
}
else {
return nil
}
}
init(singleSectionObjects: [T]) {
let section = SimpleResultsSection(objects: singleSectionObjects)
resultsSections.append(section)
}
}
现在在代码的最后一行,我尝试将SimpleResultsSection<T>
追加到self.resultsSections
,编译器拒绝我执行以下操作:
Cannot invoke 'append' with an argument list of type (SimpleResultsSection<T>)
我在这里错过了什么?
我认为<T, RS: ResultsSection where T == RS.T>
意味着编译器将能够将SimpleResultsSection<T>
解析为RS
,从而允许我append
SimpleResultsSection<T>
append
到[RS]
,但显然我缺少了一些东西。
您在这里没有做出足够强的承诺:
internal(set) var resultsSections = [RS]()
这只能保证数组充满了ResultsSection where T == RS.T
,但这可能是一个完全不相关的类。 Swift数组不是以这种方式协变的。 如果是,则将[Apple]
视为[Fruit]
,然后append(orange)
。
您想要的是:
internal(set) var resultsSections = [SimpleResultsSection<T>]()
这是对所有元素都继承自同一类的有力保证,同时仍然尊重您先前的协议,即可以将其读取为[ResultSection]
。
也就是说,我会做一些不同的事情。 除非您确实需要SimpleResultsController
能够接受多种类型的节,否则我将使用typealias而不是对其进行参数化:
class SimpleResultsController<T> : ResultsController {
internal(set) var resultsSections = [SimpleResultsSection<T>]()
...
这样,类型是SimpleResultsController<Int>
而不是SimpleResultsController<Int, SimpleResultsSection<Int>>
(这是非常麻烦的类型)。
该系统可以推断出的类型ResultsSection
从定义resultsSection
,所以没有必要typealias
它,如果你不希望(尽管它可以很方便做,为清楚)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.