我正在尝试快速构建一组通用的“NSFetchResultsController”协议(protocol),以便我可以隔离我的 UITableViewDataSource/UICollectionViewDataSource
有关数据来源和更新的地点和方式的任何具体实现。
所以我从核心 Controller 和部分的几个简单定义开始:
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>
到[RS]
,但显然我错过了一些东西。
最佳答案
您在这里没有做出足够有力的 promise :
internal(set) var resultsSections = [RS]()
这仅保证数组充满 ResultsSection where T == RS.T
,但这可能是一个完全不相关的类。 Swift 数组不是协变的。如果是的话,你就去对待[Apple]
如[Fruit]
然后append(orange)
.
您想要的是:
internal(set) var resultsSections = [SimpleResultsSection<T>]()
这是一个更强有力的 promise ,即所有元素都继承自同一个类,同时仍然尊重您之前的协议(protocol) promise ,即它可以读作 [ResultSection]
.
也就是说,我会采取一些不同的做法。除非你真的需要SimpleResultsController
为了能够接受多种类型的部分,我会强制使用类型别名而不是对其进行参数化:
class SimpleResultsController<T> : ResultsController {
internal(set) var resultsSections = [SimpleResultsSection<T>]()
...
这样,类型就是SimpleResultsController<Int>
而不是SimpleResultsController<Int, SimpleResultsSection<Int>>
(这是一种非常麻烦的类型)。
系统可以推断 ResultsSection
的类型根据 resultsSection
的定义,所以没有必要typealias
如果您不想这样做(尽管为了清楚起见,这样做会很方便)。
关于ios - Swift 泛型和协议(protocol),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29828779/