DrWhat
DrWhat

Reputation: 2490

Setting a UITableView data source and delegate in separate file - swift

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

Answers (4)

Gurjinder Singh
Gurjinder Singh

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

Rizwan Mehboob
Rizwan Mehboob

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

AechoLiu
AechoLiu

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

TheAppMentor
TheAppMentor

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

Related Questions