ios - Swift 泛型和协议(protocol)

标签 ios swift generics

我正在尝试快速构建一组通用的“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/

相关文章:

Swift - 字符串类型有固定大小吗?

ios - 在 Swift 中遵守 ViewController 中的协议(protocol)

java - 关于泛型函数的泛型错误语法 Java 1.7

c# - WebApi2 IHttpActionResult 强类型返回值

ios - Unwind Segue 和多线程

iOS:动画后更改对象位置的正确方法

ios - 加载 View 后将重复数据添加到 REALM

core-data - Core Data 可以在 iOS 上延迟获取 BLOB 属性吗?

ios - 如何更改 TableView 中索引栏的尺寸(宽度、高度)?

c# - 为什么我自己的类型会收到 System.InvalidCastException?