Swift iOS-使用泛型重用相同的TableViewController
为了实现可与泛型重用的BaseTableViewController,我阅读了一些优秀的文章 它正在工作,下面是一个快速示例:Swift iOS-使用泛型重用相同的TableViewController,swift,uitableview,generics,reusability,Swift,Uitableview,Generics,Reusability,为了实现可与泛型重用的BaseTableViewController,我阅读了一些优秀的文章 它正在工作,下面是一个快速示例: if let mountains = viewModel?.model["mountain"] as? ResponseMountain { let mountainTableViewController = BaseTableViewController(items: mountains.result, config: { (cell, item) in
if let mountains = viewModel?.model["mountain"] as? ResponseMountain {
let mountainTableViewController = BaseTableViewController(items: mountains.result, config: { (cell, item) in
cell.textLabel?.text = item.name
}, style: .plain)
mountainTableViewController.title = "Mountains"
self.navigationController?.pushViewController(mountainTableViewController, animated: true)
}
想象一下,我想显示一个来自我国的山脉的简单列表,当您选择一个山脉时,您将显示该山脉内所有可用地块的列表
这就是为什么我想重用同一个TableViewController,但使用不同的数据
我不知道如何使用泛型实现来处理它
以下是我当前的实现:
final class BaseTableViewController<Item>: UITableViewController {
var items: [Item] {
didSet {
tableView.reloadData()
}
}
let config: (UITableViewCell, Item) -> ()
init(items: [Item], config: @escaping (UITableViewCell, Item) -> (), style: UITableViewStyle) {
self.items = items
self.config = config
super.init(style: style)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .default, reuseIdentifier: "cellIdentifier")
cell.textLabel?.textColor = UIColor.white
let item = items[indexPath.row]
config(cell, item)
return cell
}
}
最终类BaseTableViewController:UITableViewController{
可变项目:[项目]{
迪塞特{
tableView.reloadData()
}
}
let config:(UITableViewCell,项)->()
初始化(items:[Item],配置:@escaping(UITableViewCell,Item)->(),样式:UITableViewStyle){
self.items=项目
self.config=config
super.init(样式:style)
}
必需的初始化?(编码器aDecoder:NSCoder){
fatalError(“初始化(编码者:)尚未实现”)
}
重写func viewDidLoad(){
super.viewDidLoad()
}
重写func tableView(tableView:UITableView,numberofrowsinssection:Int)->Int{
返回项目。计数
}
重写func tableView(tableView:UITableView,cellForRowAt indexath:indexPath)->UITableViewCell{
let cell=UITableViewCell(样式:。默认值,reuseIdentifier:“cellIdentifier”)
cell.textlab?.textColor=UIColor.white
let item=items[indexPath.row]
配置(单元格、项目)
返回单元
}
}
它高效、简单,适用于不同的用例
但是,如何使用泛型实现自定义的
didSelectRowAt
,以便使用我刚刚选择的行中的数据推送同一BaseViewController的实例呢?我会用处理cellForRowAtIndexPath
的相同方法来执行此操作。使用类型(Item)->()
将另一个闭包传递到init
。然后在didSelectRowAt
ad中调用该闭包并传递所选项目
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let item = items[indexPath.row]
didSelect(item)
}
我会像你处理
CellForRowatineXpath
一样处理它。使用类型(Item)->()
将另一个闭包传递到init
。然后在didSelectRowAt
ad中调用该闭包并传递所选项目
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let item = items[indexPath.row]
didSelect(item)
}
我可能会采取这样的方法: 首先,定义表数据项的协议以及与之配套的实现对象:
protocol TableItem {
var title: String { get set }
var items: [TableItem]? { get set }
}
struct TableItemImp: TableItem {
var title: String
var items: [TableItem]?
}
接下来定义UITableViewCell的扩展以处理单元配置:
extension UITableViewCell {
func configure<T>(with item: T) {
if let item = item as? TableItem {
// configure based on TableItem type
textLabel?.text = item.title
}
}
}
扩展UITableViewCell{
func配置(带项目:T){
如果让项目=项目作为?表项目{
//基于TableItem类型进行配置
text标签?.text=item.title
}
}
}
下面是基本tableview类的更新实现,用于处理此设置并显示另一个具有子列表中定义的列表的基本tableview控制器:
final class BaseTableViewController<Item>: UITableViewController {
let cellId = "cellIdentifier"
var items: [Item] = [] {
didSet {
tableView.reloadData()
}
}
init(items: [Item], style: UITableViewStyle) {
super.init(style: style)
configure(with: items)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
internal func configure(with items: [Item] = []) {
tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellId)
self.items = items
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath)
let item = items[indexPath.row]
cell.configure(with: item)
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let item = items[indexPath.row]
guard let vc = getDetailController(item: item) else {
return
}
present(vc, animated: true, completion: nil)
}
internal func getDetailController(item: Item) -> UITableViewController? {
guard let item = item as? TableItem, let items = item.items else {
return nil
}
return BaseTableViewController<TableItem>(items: items, style: .plain)
}
}
最终类BaseTableViewController:UITableViewController{
让cellId=“cellIdentifier”
变量项:[项]=[]{
迪塞特{
tableView.reloadData()
}
}
初始化(项:[项],样式:UITableViewStyle){
super.init(样式:style)
配置(使用:项)
}
必需的初始化?(编码器aDecoder:NSCoder){
fatalError(“初始化(编码者:)尚未实现”)
}
内部函数配置(带有项:[项]=[]){
tableView.register(UITableViewCell.self,forCellReuseIdentifier:cellId)
self.items=项目
}
重写func viewDidLoad(){
super.viewDidLoad()
}
重写func tableView(tableView:UITableView,numberofrowsinssection:Int)->Int{
返回项目。计数
}
重写func tableView(tableView:UITableView,cellForRowAt indexath:indexPath)->UITableViewCell{
let cell=tableView.dequeueReusableCell(标识符:cellId,for:indexath)
let item=items[indexPath.row]
cell.configure(使用:项)
返回单元
}
重写func tableView(tableView:UITableView,didSelectRowAt indexPath:indexPath){
取消选择行(at:indexPath,动画:true)
let item=items[indexPath.row]
guard let vc=getDetailController(项目:项目)else{
返回
}
当前(vc,动画:真,完成:无)
}
内部函数getDetailController(项:项)->UITableViewController{
guard let item=项目as?TableItem,let items=项目.items else{
归零
}
返回BaseTableViewController(项:项,样式:。普通)
}
}
我用这个设置代码测试了它
func setupTableView() {
let items = [
TableItemImp(title: "Alps", items: [
TableItemImp(title: "One", items: nil)
]),
TableItemImp(title: "Appalachian", items: [
TableItemImp(title: "Two", items: nil)
]),
TableItemImp(title: "Rockies", items: [
TableItemImp(title: "Three", items: nil)
])
]
let tableVC = BaseTableViewController<TableItem>.init(items: items, style: .plain)
present(tableVC, animated: true, completion: nil)
}
func setupTableView(){
让项目=[
TableItemImp(标题:“阿尔卑斯山”,项目:[
TableItemImp(标题:“一”,项目:无)
]),
TableItemImp(标题:“阿巴拉契亚”,项目:[
TableItemImp(标题:“两个”,项目:无)
]),
TableItemImp(标题:“落基山脉”,项目:[
TableItemImp(标题:“三”,项目:无)
])
]
让tableVC=BaseTableViewController.init(项:项,样式:.plain)
当前(tableVC,动画:真,完成:无)
}
我在
viewdispect()
中的测试视图控制器中调用此代码,它为基本表视图控制器提供顶级列表。如果单击“Rockies”,它将显示另一个列表控制器,其中显示一个标题为“Three”的单元格。我可能会采取如下方法:
首先,定义表数据项的协议以及与之配套的实现对象:
protocol TableItem {
var title: String { get set }
var items: [TableItem]? { get set }
}
struct TableItemImp: TableItem {
var title: String
var items: [TableItem]?
}
接下来定义UITableViewCell的扩展以处理单元配置:
extension UITableViewCell {
func configure<T>(with item: T) {
if let item = item as? TableItem {
// configure based on TableItem type
textLabel?.text = item.title
}
}
}
扩展UITableViewCell{
func配置(带项目:T){
如果让项目=项目为?