简体   繁体   中英

Reducing repeated code with tableviews existing in classes of different types in Swift

I have two classes with basically identical tableViewDelegate and tableViewDataSource implementation code. In the interest of leaving the code better than I found it, I figure I should try to reduce duplication. This is proving to be quite difficult. See the example code structure below:

class A : UICollectionViewCell {
//a bunch of code

}

extension A : UITableViewDataSource, UITableViewDelegate {
//A bunch of code that is nearly identical to the other class
}

class B : UIViewController {
//a bunch of code
}

extension B : UITableViewDataSource, UITableViewDelegate {
//A bunch of code that is nearly identical to the other class 
}

Both extensions use the same global variables from class A and B respectively. My initial idea was to create a superclass for class A and B that already has these delegates implemented. However, I don't think this will work because classes A and B are not extending the same class. I think I would have to go too far up the class hierarchy to find a superclass that they share.

Is there a good way to reduce this repeated code?

Thanks

You could try to create a shared UITableViewDataSource and UITableViewDelegate class that manages the data for both table views. In the example below a ViewModel that is generic over Item , can manage lists of Book or User instances. They share a CellModel interface that is used to configure the cell for the table view.

import UIKit

class ViewController: UITableViewController {
    struct User: CellModel {
        let displayName: String

        var title: String { displayName }
    }

    let viewModel = ViewModel<User>(
        items: [
            .init(displayName: "Hanna"),
            .init(displayName: "Jo")
        ]
    )

    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.dataSource = viewModel
        tableView.delegate = viewModel
    }
}

// MARK: -

class AnotherViewController: UITableViewController {
    struct Book: CellModel {
        let title: String
    }

    let viewModel = ViewModel<Book>(
        items: [
            .init(title: "Stories from A"),
        ]
    )

    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.dataSource = viewModel
        tableView.delegate = viewModel
    }
}

// MARK: -

protocol CellModel: Hashable {
    var title: String { get }
}

final class ViewModel<Item: CellModel>: NSObject, UITableViewDataSource, UITableViewDelegate {

    let items: [Item]

    init(items: [Item]) {
        self.items = items
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        items.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: "CellID") else {
            return UITableViewCell(style: .default, reuseIdentifier: "CellID")
        }

        let item = items[indexPath.row]
        var content = cell.defaultContentConfiguration()
        content.text = item.title
        cell.contentConfiguration = content
        return cell
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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