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