Reputation: 2490
If I would like to have the same basic UITableView appearing in two different scenes, is it a good idea to use one datasource and delegate location for both tables?
I wanted to try this, but when I select the table view in IB and try to drag the line to a custom class of UITableView file, or even to another custom view controller, it will not connect. It only seems possible to make the current View Controller into the table's datasource and delegate(?).
I'm wondering if this is at least similar to this question, but even if it is, how is this done in swift (and perhaps there is a new way to do this).
Upvotes: 3
Views: 11309
Reputation: 10299
Swift 4.1. You can create separate class and inherit it from UITableViewDataSource and UITableViewDelegate class. Here, I am implementing UITableViewDataSource() methods in DataSource class. You also need to confirm NSObject so that we don’t have to fiddle with the @objc and @class keywords because UITableViewDataSource is an Objective-C protocol.
import Foundation
import UIKit
class DataSource: NSObject, UITableViewDataSource {
var formData: [FormData]? = nil
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.formData?.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell")
let label = cell?.contentView.viewWithTag(100) as? UILabel
let type = self.formData![indexPath.row]
label?.text = type.placeHolder
return cell!
}
}
Now, We will set DataSource to UITableView. If we crate separate class then we have to pass data to DataSource class.
class ViewController: UIViewController {
@IBOutlet weak var tblView: UITableView!
var formData: [FormData]? = nil
var dataSource = DataSource()
override func viewDidLoad() {
super.viewDidLoad()
formData = FormData.array
dataSource.formData = formData // Pass data to DataSource class
tblView.dataSource = dataSource // Setting DataSource
}
}
In similar way you can implement UITableViewDelegate in separate class. The other way to separate DataSource and Delegate is by creating extension of your viewController. Even you can crate separate class where you can only define extensions for your view controller. In you define extension then you don't need to pass data.
class ViewController: UIViewController {
@IBOutlet weak var tblView: UITableView!
var formData: [FormData]? = nil
override func viewDidLoad() {
super.viewDidLoad()
formData = FormData.array
tblView.dataSource = self
}
}
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.formData?.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell")
let label = cell?.contentView.viewWithTag(100) as? UILabel
let type = self.formData![indexPath.row]
label?.text = type.placeHolder
label?.backgroundColor = UIColor.gray
return cell!
}
}
Upvotes: 7
Reputation: 1373
Here is a code example showing different Datasource and delegates for UITableView.
Code in Swift
import UIKit
// MARK: Cell
class ItemCell: UITableViewCell{
var label: UILabel!
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
label = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: 20))
label.textColor = .black
label.backgroundColor = .yellow
contentView.addSubview(label)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
// MARK: Main View Controller
class BlueViewController: UIViewController{
var tableView: UITableView!
var myDataSourse: MyTVDataSource!
var myDelegate: MyTVDelegate!
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .blue
tableView = UITableView()
myDataSourse = MyTVDataSource(tableView: tableView)
myDelegate = MyTVDelegate()
myDelegate.presentingController = self
tableView.dataSource = myDataSourse
tableView.delegate = myDelegate
tableView.register(ItemCell.self, forCellReuseIdentifier: "Cell")
self.view.addSubview(tableView)
self.tableView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
tableView.topAnchor.constraint(equalTo: view.topAnchor, constant: 0),
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0),
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0),
tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0)
])
}
}
extension BlueViewController: BluePresenting{
func currentSelected(_ indexPath: IndexPath) {
print(indexPath)
}
}
// MARK: TableViewDelegate
protocol BluePresenting: class {
func currentSelected(_ indexPath: IndexPath)
}
class MyTVDelegate: NSObject,UITableViewDelegate{
var presentingController: BluePresenting?
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
presentingController?.currentSelected(indexPath)
}
}
// MARK: TableView DataSource
class MyTVDataSource: NSObject, UITableViewDataSource{
private var tableView: UITableView
private var items = ["Item 1","item 2","item 3","Item 4"]
init(tableView: UITableView) {
self.tableView = tableView
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = ItemCell(style: .default, reuseIdentifier: "Cell")
cell.label.text = items[indexPath.row]
return cell
}
}
Upvotes: 5
Reputation: 18368
You can implement a custom class object, and implement the UITableViewDataSource
methods for this class.
@interface MyDataSource : NSObject <UITableViewDataSource>
//...
@end
And then, the UITableView
has properties, delegate
and dataSource
.
Assign right objects to those properties.
MyDataSource ds = ... ///< Initialize the dataSource object.
self.tableView.dataSource = ds; ///< Let ds be the dataSource of `self.tableView`
self.tableView.delegate = .... ///< Assign the delegate, generally it is `self`.
Upvotes: 3
Reputation: 1089
Each Tableview should have its own Tableview controller. This is in accordance with the Model View Controller Design Pattern.
If the data in the the two tables are the same, you could have a common class serve as the dataSource.
Upvotes: 2