我正在尝试在swift中构建一组通用的"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
,从而允许我将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
才能接受多种类型的部分,否则我会用类型别名来强制它,而不是参数化它:
class SimpleResultsController<T> : ResultsController {
internal(set) var resultsSections = [SimpleResultsSection<T>]()
...
这样,类型是SimpleResultsController<Int>
而不是SimpleResultsController<Int, SimpleResultsSection<Int>>
(这是一个非常繁琐的类型)。
系统可以从resultsSection
的定义中推断出ResultsSection
的类型,因此如果您不想typealias
,则无需(尽管为了清楚起见,这样做可能很方便)。