Reckoner
Reckoner

Reputation: 1041

Implementing VIPER architecture in iOS

I am implementing my project as per VIPER for the first time and I have some doubts regarding its implementation.This is what I have done so far:
1)Implement Login page
STEPS
i)User taps login button(on view controller).

ii)I have a request model where I store 'username' and 'password'.This is the structure of model:

struct Login{
    struct Request{
        var txt_email:String!
        var txt_password:String!
    }  
    struct Response {
        var homeData:Dictionary<String,Any>
    }
}

So I pass this Request object to the Interactor.

iii)In Interactor,I have different Workers(Worker class object methods) assigned to perform different tasks such as email validation,empty textFields validation etc.If all is well,the worker api method hits login API and passes the response back to Interactor via delegation.

iv)Update the 'Response' model in the above structure.

v)Now that I have the response in Interactor,I pass this response to the Presenter to do some manipulations according to what controller needs to display to the user.

vi)Pass the data to the Controller and it presents it to user.

Question 1:Am I doing everything right.If no , please show me the right way.If yes , please tell me if there is some room for improvement.
Question 2:I need to implement UITableView and UICollectionView on the home page and I think extensions is the way to go for them.I will follow the same strategy for Home page as well.But suppose , in 'didSelectRowAtIndexPath' , I need to show a pop up to user and I think it will be better for ViewController to ask Presenter directly about the data.But is it the correct way?If not what is the correct way?
Question 3:should I pass data from cellForRowAtIndexPath: to actual cell(MyCell:UITableViewCell) class methods and then assign values to UIElements?Yes or no?

Upvotes: 2

Views: 1613

Answers (2)

Mr.Javed Multani
Mr.Javed Multani

Reputation: 13274

Reference: https://medium.com/@javedmultani16/viper-architecture-viper-64f6cd91e6ec

We developer basically uses the MVC,MVP or MVVM architecture for the development as per the requirement. It is mattering which architecture you are choose to develop the application. Many factors affecting for selection of the software architecture like system designs, requirements, time-lines etc.

In Viper architecture, each block corresponds to an object with specific tasks, inputs and outputs. It is very similar to workers in an assembly line: once the worker completes its job on an object, the object is passed along to the next worker, until the product is finished.

V (View): View is responsible for the UI updates and show whatever the presenter tells it.

I (Interactor) : The Interactor is responsible for fetching data from the model layer, and its implementation is totally independent of the user interface.All the business logic written inside the Interactor. E.g. Get User Data API call written in the Interactor.

P (Presenter): Presenter performing role as intermediator it gets data from interaction and passes to View. (It may be data or any user action)

E (Entity): Basically it is contains the Object Model which is used by Interactor. E.g. Student,Friend,College etc.

R (Router): It contains navigation logic for the application. E.g. Next button action shows second screen.

Morever, I’ve use the PROTOCOL, which contains all the rules and work-flow for the particular module of the application. In iOS all the protocols written in the separate protocol swift file for each module.

Morever, I’ve use the PROTOCOL, which contains all the rules and work-flow for the particular module of the application. In iOS all the protocols written in the separate protocol swift file for each module.

Let’s see the file structure of it: enter image description here

Benefits:

-All the modules are independent so VIPER is really good for large teams.

-It makes the source code cleaner, more compact and reusable

-It easier to adopt TDD (Test Driven Development)

-You can add easily new features to the existing application without changing other modules possibly.

-It can be applies SOLID principles.

-Reduced number of merge conflicts.

-It Makes it easy to write automated tests since your UI logic is separated from the business logic

struct Person { // Entity (usually more complex e.g. NSManagedObject)
    let firstName: String
    let lastName: String
}
struct GreetingData { // Transport data structure (not Entity)
    let greeting: String
    let subject: String
}
protocol GreetingProvider {
    func provideGreetingData()
}
protocol GreetingOutput: class {
    func receiveGreetingData(greetingData: GreetingData)
}
class GreetingInteractor : GreetingProvider {
weak var output: GreetingOutput!
func provideGreetingData() {
        let person = Person(firstName: "David", lastName: "Blaine") // usually comes from data access layer
let subject = person.firstName + " " + person.lastName
        let greeting = GreetingData(greeting: "Hello", subject: subject)
        self.output.receiveGreetingData(greeting)
   } 
}
protocol GreetingViewEventHandler {
    func didTapShowGreetingButton()
}
protocol GreetingView: class {
    func setGreeting(greeting: String)
}
class GreetingPresenter : GreetingOutput, GreetingViewEventHandler {
    weak var view: GreetingView!
    var greetingProvider: GreetingProvider!
func didTapShowGreetingButton() {
        self.greetingProvider.provideGreetingData()
}
func receiveGreetingData(greetingData: GreetingData) {
        let greeting = greetingData.greeting + " " + greetingData.subject
        self.view.setGreeting(greeting)
   }
 }
class GreetingViewController : UIViewController, GreetingView {
    var eventHandler: GreetingViewEventHandler!
    let showGreetingButton = UIButton()
let greetingLabel = UILabel()
override func viewDidLoad() {
 super.viewDidLoad()
 self.showGreetingButton.addTarget(self, action: "didTapButton:", forControlEvents:.TouchUpInside)

 }
func didTapButton(button: UIButton) {
        self.eventHandler.didTapShowGreetingButton()
}
func setGreeting(greeting: String) {
        self.greetingLabel.text = greeting
}
// layout code goes here
}
// Assembling of VIPER module, without Router
let view = GreetingViewController()
let presenter = GreetingPresenter()
let interactor = GreetingInteractor()
view.eventHandler = presenter
presenter.view = view
presenter.greetingProvider = interactor
interactor.output = presenter


Upvotes: 2

jonaszmclaren
jonaszmclaren

Reputation: 2489

Regarding Question 2 and 3, here's answer with my simple example of Viper app using UITableView: https://stackoverflow.com/a/45709546/3990005.

The ViewController does not speak to the Interactor, but to presenter, so on cellForRowAtIndexPath: you should call the Presenter with information, which IndexPath was selected.

Regarding cell creation, what I like to do is have a setup method in UITableViewCell class, and in ViewController ask Presenter for data and pass it to the cell. Some of it is visible in the above example, and here's cell's setupCell method:

func setupCell(withSong: song) {
    titleLabel.text = song.title
    descriptionLabel.text = song.description
}

Upvotes: 1

Related Questions