[英]Swift Generics & Protocols
I'm trying to build a generic 'NSFetchResultsController'-like set of protocols in swift so that I might isolate my UITableViewDataSource/UICollectionViewDataSource
implementations from any specifics about where and how the data is being sourced and updated. 我正在尝试快速构建通用的类似于“ NSFetchResultsController”的协议集,以便可以将UITableViewDataSource/UICollectionViewDataSource
实现与任何有关在何处以及如何获取和更新数据的细节隔离开来。
So I began with a couple of simple definitions of the core controller and sections thus: 因此,我首先对核心控制器及其部分进行了一些简单的定义:
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 }
}
Following this a couple of simple implementations just holding everything in arrays thus: 在此之后的几个简单的实现仅将所有内容保存在数组中:
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)
}
}
Now on the last line of code where I try to append a SimpleResultsSection<T>
to self.resultsSections
the compiler denies me with: 现在在代码的最后一行,我尝试将SimpleResultsSection<T>
追加到self.resultsSections
,编译器拒绝我执行以下操作:
Cannot invoke 'append' with an argument list of type (SimpleResultsSection<T>)
What have I missed here? 我在这里错过了什么?
I thought that <T, RS: ResultsSection where T == RS.T>
would mean that the compiler would be able to resolve SimpleResultsSection<T>
to an RS
and thus allow me to append
a SimpleResultsSection<T>
to an [RS]
, but clearly I'm missing something. 我认为<T, RS: ResultsSection where T == RS.T>
意味着编译器将能够将SimpleResultsSection<T>
解析为RS
,从而允许我append
SimpleResultsSection<T>
append
到[RS]
,但显然我缺少了一些东西。
You're not making as strong-enough promise here: 您在这里没有做出足够强的承诺:
internal(set) var resultsSections = [RS]()
This only promises that the array is full of ResultsSection where T == RS.T
, but that could be a completely unrelated class. 这只能保证数组充满了ResultsSection where T == RS.T
,但这可能是一个完全不相关的类。 Swift arrays are not covariant in that way. Swift数组不是以这种方式协变的。 If they were, you to treat [Apple]
as [Fruit]
and then append(orange)
. 如果是,则将[Apple]
视为[Fruit]
,然后append(orange)
。
What you want here is: 您想要的是:
internal(set) var resultsSections = [SimpleResultsSection<T>]()
That's a stronger promise that all of the elements inherit from the same class, while still respecting your earlier protocol promise that it could be read as [ResultSection]
. 这是对所有元素都继承自同一类的有力保证,同时仍然尊重您先前的协议,即可以将其读取为[ResultSection]
。
That said, I would do it a bit differently. 也就是说,我会做一些不同的事情。 Unless you really need SimpleResultsController
to be able to accept multiple types of sections, I would force that with a typealias rather than parameterizing it: 除非您确实需要SimpleResultsController
能够接受多种类型的节,否则我将使用typealias而不是对其进行参数化:
class SimpleResultsController<T> : ResultsController {
internal(set) var resultsSections = [SimpleResultsSection<T>]()
...
This way, the type is SimpleResultsController<Int>
rather than SimpleResultsController<Int, SimpleResultsSection<Int>>
(which is a very cumbersome type). 这样,类型是SimpleResultsController<Int>
而不是SimpleResultsController<Int, SimpleResultsSection<Int>>
(这是非常麻烦的类型)。
The system can infer the type of ResultsSection
from the definition of resultsSection
, so there's no need to typealias
it if you don't want to (though it can be handy to do that for clarity). 该系统可以推断出的类型ResultsSection
从定义resultsSection
,所以没有必要typealias
它,如果你不希望(尽管它可以很方便做,为清楚)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.