Conforming to UItableviewdelegate and UItableviewdatasource in Swift

Conforming to UITableViewDelegate and UITableViewDatasource in Swift?

First of all, that is completely independent of which language
you use, Swift or Objective-C.

But there are two different cases which may cause the confusion:

A UITableViewController subclass:

UITableViewController already conforms to UITableViewDataSource and UITableViewDelegate. It has a tableView property,
whose dataSource and delegate property are already set to self.

In your subclass, you typically override the
data source and delegate methods.

A UIViewController subclass with a UITableView property:

Here you have defined a UITableView property in your subclass
and initialize it in your code, or
connect it to a table view in the interface builder.

In this case you have to set the dataSource and delegate
property of the tableview, either in code or in the interface
builder, as explained in luk2302's answer.

If data source and delegate are the view controller itself,
then you have to declare the protocol conformance explicitly,
and implement the
data source and delegate methods (but without overriding
a superclass method).


Of course, in both cases, the table view data source and the delegate
can be set to a different object, it does not have to be
the view controller itself.

Can ViewModel class conforms to UITableviewDelegate and UITableViewDataSource in iOS as per MVVM

Yes you can, set any object that conforms to those protocols as the delegate, data source or separate them to different objects, anything and anyone can implement a protocol.

When writing a complex table view data source or delegate, It’s better to define a type whose purpose is to be a table view’s data source. This helps to better separate responsibilities between objects.

You can find an example by Apple implementing different objects as the table/collection View's data source here:
Advanced User Interfaces with Collection Views by apple

These object/s doesn't have to be your viewModel, but please see a good example when it is:
MVVM with viewModel as the table datasource

UITableView does not conform to protocol UITableViewDataSource error

You have incorrectly set up your ViewController. Either create a UITableViewController which is just a UITableView, or add a UITableView to a UIViewController (Like you have almost done).

The didSelectRowAt method will allow you to segue to a new viewController, but in my examples only if it is set up correctly in a storyboard.


UITableViewController option

class TableViewController: UITableViewController {

override func viewDidLoad() {
super.viewDidLoad()
}

// MARK: - Table view data source

override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 0
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return 0
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier", for: indexPath)
// Configure the cell...
return cell
}

// MARK: - Table view delegate

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: false)
performSegue(withIdentifier: "SegueIdentifier", sender: self)
}

UIViewController option
(The UITableView will need to be added through a Storyboard in this example)

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

@IBOutlet weak var tableView: UITableView!

override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}

// MARK: - Table view data source

func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 0
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return 0
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier", for: indexPath)
// Configure the cell...
return cell
}

// MARK: - Table view delegate

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: false)
performSegue(withIdentifier: "SegueIdentifier", sender: self)
}

Here is an example project to work from

Why do I have to set the dataSource and delegate to self?

Since you said you're learning Swift just thought of writing an elobrate answer. All the other answers already explains why you need to set the delegate to self or any instance of a class. But still I thought of writing this answer just to give more insight.

Let me explain what UITableViewDelegate & UITableViewDataSource are. Both UITableViewDelegate & UITableViewDataSource are protocols. What is a protocol? You can think protocol as a set of actions.

For example UITableViewDataSource has set of actions/methods like
tableView(:numberOfRowsInSection:), tableView( tableView: UITableView,
cellForRowAtIndexPath indexPath: NSIndexPath)
and so on.

What this protocol implies is that if you want to supply your custom data to the tableview, you need to conform to this protocol i.e. implement the non optional methods of the protocol(you can ignore optional methods if any).

Similarly, UITableViewDelegate has set of methods like, tableView(_ tableView: UITableView,
heightForRowAtIndexPath indexPath: NSIndexPath)
, tableView(_ tableView: UITableView,
didSelectRowAtIndexPath indexPath: NSIndexPath)
and so on.

UITableViewDelegate protocol implies that you need to conform to the protocol if you want to get notified when user interactions happens at tableview for example when user taps on a cell of tableview.

So now, why are you setting

tableView.dataSource = self
tableView.delegate = self

is because you are implementing the protocols (or conforming to protocols )in your ViewController, TableViewDatasource protocol to supply your own data to the tableview, TableViewDelegate protocol to notify your ViewController class when user interacts with your tableview.

Actually you'll not be setting protocol conformance to self always, you can set it to instance of any class which implements the protocol.

Hope this Helps.

For more reference on protocols you can go through this: Swift 2 Tutorial Part 3: Tuples, Protocols, Delegates, and Table Views

Does Not Conform To Protocol 'UITableViewDataSource' Error?

If you start typing the name of the functions Xcode will auto-complete them for you. Here's an example that'll help you. (And doc. in the link)

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

UITableView delegate using extensions swift

You can divide in a extension, as you can check in the apple documentation section about Extensions handling Protocols.

Here I have implement a minimum code doing what you ask, check it out.

  import UIKit

class TableViewViewController: UIViewController {
@IBOutlet weak var table: UITableView!

override func viewDidLoad() {
super.viewDidLoad()
table.delegate = self
table.dataSource = self
}
}

extension TableViewViewController: UITableViewDelegate,UITableViewDataSource {

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("reuseIdentifier", forIndexPath: indexPath)
cell.textLabel!.text = "it works"
return cell
}

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

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
}

swift protocol with uitableviewdatasource

If you want to implement these data source methods and reuse them, just define a data source class that implements them. And then rather than implementing the delegate methods in the view controller, instantiate a data source object, keep a strong reference to it, and specify it as the data source for the table view.

For example:

class DataSource: NSObject, UITableViewDataSource {

func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 3
}

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
// configure cell here
return cell
}
}

class ViewController: UITableViewController {

let dataSource = DataSource()

override func viewDidLoad() {
super.viewDidLoad()

tableView.dataSource = dataSource
}

}

ViewController' does not conform to protocol 'UITableViewDataSource' swift

The problem is that you are using lower version of swift not swift 3.0, method cellForRowAt indexPath is work with swift 3.0, so you need to use this cellForRowAtIndexPath instead of that.

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("MenuCell", forIndexPath: indexPath) as! MenuCell
if (indexPath as NSIndexPath).row < itemsArray.count {
let option = itemsArray[(indexPath as NSIndexPath).row]
cell.titleLabel?.text = option
}
return cell
}


Related Topics



Leave a reply



Submit