I have a view controller which contains a table view, so I want to ask where should I put table view data source and delegate, should it be an external object or I can write it in my view controller if we say about VIPER pattern.
Normally using pattern I do this:
In viewDidLoad I request some flow from presenter like self.presenter.showSongs()
Presenter contains interactor and in showSongs method I request some data from interactor like: self.interactor.loadSongs()
When songs are ready to passing back to view controller I use presenter one more time to determine how this data should be display in view controller. But my question what should I do with datasource of table view?
Create an NSObject Class and use it as the custom data source. Define your delegates and datasources in this class.
Declare two typealias for call backs regarding one for fill data in UITableViewCell and another one for when the user taps a row.
Here are my different points from the answers:
1, View should never ask Presenter for something, View just need to pass the events(
viewDidLoad()/refresh()/loadMore()/generateCell()
) to the Presenter, and the Presenter responses which events the View passed to.2, I don't think the Interactor should have a reference to the Presenter, the Presenter communicates with Interactor via callbacks(block or closure).
First of all your View shouldn't ask data from Presenter - it's violation of VIPER architecture.
The View is passive. It waits for the Presenter to give it content to display; it never asks the Presenter for data.
As for you question: It's better to keep current view state in Presenter, including all data. Because it's providing communications between VIPER parts based on state.
But in other way Presenter shouldn't know anything about UIKit, so UITableViewDataSource and UITableViewDelegate should be part of View layer.
To keep you ViewController in good shape and do it in 'SOLID' way, it's better to keep DataSource and Delegate in separate files. But these parts still should know about presenter to ask data. So I prefer to do it in Extension of ViewController
All module should look something like that:
View
ViewController.h
ViewController.m
ViewController+TableViewDataSource.h
ViewController+TableViewDataSource.m
ViewController+TableViewDelegate.h
ViewController+TableViewDelegate.m
Presenter
Presenter.m
Interactor
Interactor.m
Very good question @Matrosov. First of all I want to tell you that, it's all about responsibility segregation among VIPER components such as View, Controller, Interactor, Presenter, Routing.
It's more about tastes one changes over the time during development. There are many architectural patterns out there like MVC, MVVP, MVVM etc. Over time when our taste changes, we change from MVC to VIPER. Someone changes from MVVP To VIPER.
Use your sound vision by keeping class size small in number of lines. You can keep datasource methods in ViewController itself Or create a custom object that conforms to UITableViewDatasoruce protocol.
My aim to keep view controllers slim and every method and class follow Single responsibility principle.
Viper helps to create highly cohesive and low coupled software.
Before using this model of development, one should have sound understanding of distribution of responsibility among classes.
Once you have basic understanding of Oops and Protocols in iOS. You will find this model as easy as MVC.
1) First of all, View is
passive
an should not ask data for the Presenter. So, replaceself.presenter.showSongs()
byself.presenter.onViewDidLoad()
.2) On your Presenter, on the implementation of
onViewDidLoad()
you should normally call the interactor to fetch some data. And interactor will then call, for example,self.presenter.onSongsDataFetched()
3) On your Presenter, on the implementation of
onSongsDataFetched()
you should PREPARE the data as per the format required by the View and then callself.view.showSongs(listOfSongs)
4) On your View, on the implementation of
showSongs(listOfSongs)
, you should setself.mySongs = listOfSongs
and then calltableView.reloadData()
5) Your TableViewDataSource will run over your array
mySongs
and populate the TableView.For more advanced tips and helpful good practices on VIPER architecture, I recommend this post: https://www.ckl.io/blog/best-practices-viper-architecture (sample project included)
Example in Swift 3.1, maybe will be useful for someone:
View
Presenter
Interactor
Wireframe