Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Routing Viper architecture

How to create good routing in project on Viper architecture? I start create file for routing but i don't understand what i must do next.

I create a file wireframe first controller and wireframe protocol:

//  ChooseLanguageWireframeProtocol.swift

import UIKit

@objc protocol ChooseLanguageWireframeProtocol {
    func presentChooseLanguageViewControllerWindow()
    func presentAuthScreenViewController()
}

in file wireframe i add:

//  ChooseLanguageWireframe.swift

import UIKit

class ChooseLanguageWireframe: NSObject , ChooseLanguageWireframeProtocol{

    var chooseLanguageScreenViewController: ChooseLanguageViewController?
    var window: UIWindow?

    func presentChooseLanguageViewControllerWindow() {
        let chooseLanguageViewController = UIStoryboard.init(name: "ChooseLanguage", bundle: nil).instantiateViewController(withIdentifier: "ChooseLanguage") as? ChooseLanguageViewController
        self.chooseLanguageScreenViewController = chooseLanguageViewController
        self.window!.rootViewController = chooseLanguageScreenViewController
        self.window!.makeKeyAndVisible()
    }
    func presentAuthScreenViewController() {

    }
}

After i create RootWireframe

//  RootWireframe.swift

import UIKit

class RootWireframe: NSObject {

    let chooseLanguageScreenWireframe : ChooseLanguageWireframe?

    override init() {
     //What i must init??
    }

    func application(didFinishLaunchingWithOptions launchOptions: [AnyHashable: Any]?, window: UIWindow) -> Bool  {
        self.chooseLanguageScreenWireframe?.window = window
        return true
    }

}

In file AppDelegate i change only

var window: UIWindow?
    let rootWireframe = RootWireframe()

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        self.rootWireframe.application(didFinishLaunchingWithOptions: launchOptions as [NSObject : AnyObject]?, window: self.window!)
    }

What i must add or change for correctly work?

like image 357
Andrei Trotsko Avatar asked Oct 17 '22 14:10

Andrei Trotsko


2 Answers

One way to do it is to inherit from UINavigationController and do the routing logic in there. You may end up with multiple classes doing routing in different parts of your application depending on your task.

But like with any cromulent buzzword you firstly have to ask yourself if the "solutuon" solves more issues than it creates.

It starts to make sense when you get two dozen screens and start to get lost in the very same issue that got resolved ages ago by adding storyboards to plain old xibs.

So you really have to step back and ask yourself if you really want to follow this cromulent architecture creating lots and lots of classes in the process, a maze that will be hardly more readable than a standard MVC project.

If you can not use storyboards and want to use VIPER do so, if you can use storyboards do VIPE :-)

But in most projects the datamodel is so pathetically simple and the presentation is so tightly coupled that you have zero need in UIViewController defattening.

And I suspect that the cure applied by the most viper affictionados is worse than the decease itself.

like image 141
Anton Tropashko Avatar answered Oct 20 '22 23:10

Anton Tropashko


2 possibilities:

Change the init of your rootViewframe to accept your dependency and initialize it. And btw your variable type should not be the real type but the protocol, so you can mock it easily in tests

let chooseLanguageScreenWireframe : ChooseLanguageWireframeProtocol?

override init(chooseLanguage: ChooseLanguageWireframeProtocol) {
self.chooseLanguageScreenWireframe = chooseLanguage
}

And then create your chooseLanguageWireframe implementation in the appdelegate and pass it in the constructor. This makes the dependency clear and visible. You can also remove the optionality, since you always initialize it.

Or solution 2 Create the chooseLanguageWireframe in the appdelegate and inject it there outside constructor

lazy var rootWireframe = {
let r = RootWireframe()
r.chooseLanguageScreenWireframe = self.chooseLanguageScreenWireframe
return r
}

In any case, you need to instantiate your dependencies somewhere, they cannot get created automatically. You usually do that with factories and with the help of a dependency injection framework (check SwiftInject or Typhoon)

Also, declare all your dependencies with protocols type, it is the purpose of the VIPER architecture to simplify testing and mocking with isolations between actors

like image 24
Marco Pappalardo Avatar answered Oct 20 '22 22:10

Marco Pappalardo