Swift 通过 UITableVIew 中的部分进行通用基本搜索功能

Swift generic base search functionality through section in UITableVIew

我根据这个tutorial设计了我的搜索组件。

如果我在 table 视图中有一个部分,它会很好用,所以我不需要担心嵌套的东西。

这是我的代码:

import UIKit

protocol Searchable {
    var query: String { get }
    var isSelected: Bool { get set }
}

class BaseSearchDataSource<V, T: Searchable>: NSObject, UITableViewDataSource where V: BaseTableViewCell<T> {

    private var models: [T]
    private let configureCell: CellConfiguration
    typealias CellConfiguration = (V, T) -> V
    private var searchResults: [T] = []
    private var isSearchActive: Bool = false

    init(models: [T], configureCell: @escaping CellConfiguration) {
        self.models = models
        self.configureCell = configureCell
    }

    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return isSearchActive ? searchResults.count : models.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell: V = tableView.dequeueReusableCell(forIndexPath: indexPath)
        let model = getModelAt(indexPath)
        return configureCell(cell, model)
    }

    func getModelAt(_ indexPath: IndexPath) -> T {
        return isSearchActive ? searchResults[indexPath.item] : models[indexPath.item]
    }

    func search(query: String) {
        isSearchActive = !query.isEmpty
        searchResults = models.filter {
            let queryToFind = [=11=].query.range(of: query, options: NSString.CompareOptions.caseInsensitive)
            return (queryToFind != nil)
        }
    }
}

我有这个 class 实现,它符合指定的协议:

class MuscleSelectableItem: Searchable {

var query: String {
    return name
}

var isSelected: Bool

let name: String
let muscle: MusclEntity

init (isSelected: Bool, name: String, muscle: MusclEntity) {
    self.isSelected = isSelected
    self.name = name
    self.muscle = muscle
}
}

所以现在当我使用父 BaseSearchDataSource 的子 class 时,我可以简单地指定一个 class 我想加载到我的 table 视图并制作这个 class可搜索。所以现在我的 var models: [T] 将模型表示为 [MuscleSelectableItem]

我知道我需要使用一些带有嵌套项目的部分对象:

class TableViewSection {
var items: [MuscleSelectableItem]
}

但是我为 items.

指定了具体类型 [MuscleSelectableItem] 的上面代码的问题

如何声明 [T] 这将是一个 TableViewSectionitems 直到我们在 subclasses 中告诉编译器我们想要使用什么类型之前是未定义的items,比如搜索城市、肌肉或书籍或任何其他实体,因此 items 可以是其中任何一个

我也不喜欢我的协议包含搜索和 select 功能,如何正确分离它?

您也可以在包装器中使用泛型。在上面的例子中,它看起来像这样:

class TableViewSection<T> {
    var items = [T]()

}

您还可以构建一个 TableDataSource class,它有一个 table 视图部分的数组,这将提供机会,例如基于 indexPath 的下标,然后按顺序使其符合收集协议获得过滤、计数等功能

Also what I don't like as well that my protocol contains search and select functionality, how to separate it correctly?

Swift 允许使用类型别名组合更小协议的协议。以上可以这样划分:

protocol Searchable {
    var query: String { get }
}

protocol Selectable {
    var isSelected: Bool { get set }
}

typealias SearchAndSelectable = Searchable & Selectable

SearchAndSelectable 类型的变量将同时具有 'query' 和 'isSelected' 值,这对于可以利用两种协议类型的通用约束或函数来说很方便.