繁体   English   中英

Swift泛型与协议

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM