I'm trying to keep my view controllers clean as described in this article objc.io Issue #1 Lighter View Controllers. I tested this method in Objective-C and it works fine. I have a separate class which implements UITableViewDataSource
methods.
#import "TableDataSource.h" @interface TableDataSource() @property (nonatomic, strong) NSArray *items; @property (nonatomic, strong) NSString *cellIdentifier; @end @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; } @end
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 super.init() } 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 init
method of TableDataSource
and the items and the cell identifier gets passed fine. I had to declare the UITableViewDataSource
methods public
and remove the override
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.
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() { super.viewDidLoad() dataSource = TableDataSource(items: ["One", "Two", "Three"], cellIdentifier: "Cell") tableView.dataSource = dataSource } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With