I'm trying to separate dataSource and delegate from viewController to prevent the viewController from being messy. I read through some posts and found I can separate dataSource like below, create a class to represent dataSource
:
import UIKit
class DataSource: NSObject, UITableViewDataSource, UITableViewDelegate {
var movies = [String]()
//MARK: - UITableViewDataSource
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return movies.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cellIdentifier", forIndexPath: indexPath) as UITableViewCell
cell.textLabel?.text = movies[indexPath.row]
return cell
}
}
My question is: What should I do if I want to use properties or call methods of viewController
class in DataSource
class? For example, I want to call presentViewController
when the user select a cell:
func tableView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
//do something here
presentViewController(viewController!, animated: true, completion: nil)
}
You can handle a selected callback:
class DataSource: NSObject, UITableViewDataSource, UITableViewDelegate {
var movies = [String]()
private var selectedCallback = ((NSIndexPath)->Void)?
func selectedItemAtIndex(callback:(NSIndexPath) -> Void) {
selectedCallback = callback
}
}
callback:
func tableView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
//do something here
if let callback = selectedCallback {
callback(indexPath)
}
}
Using:
dataSource.selectedItemAtIndex() {
[weak self] indexPath in
// do something ...
// presentViewController(viewController!, animated: true, completion: nil)
}
You don't want to couple your datasource with navigation logic like presentViewController
. Instead, your datasource can have a delegate, and the datasource will tell the delegate that a certain action was performed by the user. This way, the delegate does not need to know about details like indexPaths; the delegate of the datasource can be the viewController that owns both the collectionView and the dataSource of the collectionView.
UIViewController: has properties UICollectionView and a property YourDataSource. And the viewController sets itself as delegate of YourDataSource instance. In the implementation of YourDataSource's collectionViewDidSelectItemAtIndexPath
, you can retrieve the movie that lives at that indexPath, and call the delegate with a method like
func dataSource(dataSource: YourDataSource, didSelectMovie movie: YourMovieClass)
This will nicely make the viewController unaware of how this movie was selected, and can just a create, setup and present a new viewController for this movie.
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