Isuru Isuru - 1 year ago 72
iOS Question

Separating Data Source to another class in Swift

I'm trying to keep my view controllers clean as described in this article Issue #1 Lighter View Controllers. I tested this method in Objective-C and it works fine. I have a separate class which implements


#import "TableDataSource.h"

@interface TableDataSource()

@property (nonatomic, strong) NSArray *items;
@property (nonatomic, strong) NSString *cellIdentifier;


@implementation TableDataSource

- (id)initWithItems:(NSArray *)items cellIdentifier:(NSString *)cellIdentifier {
self = [super init];
if (self) {
self.items = items;
self.cellIdentifier = cellIdentifier;
return self;

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.items.count;

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:self.cellIdentifier forIndexPath:indexPath];

cell.textLabel.text = self.items[indexPath.row];

return cell;


From the tableview controller, all I have to do is instantiate a instance of this class and set it as the tableview's data source and it works perfectly.

self.dataSource = [[TableDataSource alloc] initWithItems:@[@"One", @"Two", @"Three"] cellIdentifier:@"Cell"];
self.tableView.dataSource = self.dataSource;

Now I'm trying to do the same in Swift. First here's my code. Its pretty much of a translation of the Objective-C code above.

import Foundation
import UIKit

public class TableDataSource: NSObject, UITableViewDataSource {

var items: [AnyObject]
var cellIdentifier: String

init(items: [AnyObject]!, cellIdentifier: String!) {
self.items = items
self.cellIdentifier = cellIdentifier


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

public func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as UITableViewCell

cell.textLabel?.text = items[indexPath.row] as? String

return cell


And I call it like this.

let dataSource = TableDataSource(items: ["One", "Two", "Three"], cellIdentifier: "Cell")
tableView.dataSource = dataSource

But the app crashes with the following error.

-[NSConcreteNotification tableView:numberOfRowsInSection:]: unrecognized selector sent to instance

I checked the
method of
and the items and the cell identifier gets passed fine. I had to declare the
and remove the
keyword otherwise it would give compile time errors.

I'm clueless on what's going wrong here. Can anyone please help me out?

Thank you.

Answer Source

Create a property for data source and use it with your tableview.

class ViewController: UIViewController {

  @IBOutlet weak var tableView: UITableView!
  var dataSource:TableDataSource!

  override func viewDidLoad() {

    dataSource = TableDataSource(items: ["One", "Two", "Three"], cellIdentifier: "Cell")

   tableView.dataSource = dataSource

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download