Viper architecture

  • View
    375

  • Download
    0

  • Category

    Mobile

Preview:

Citation preview

Екатерина КоровкинаИнженер-разработчик iOS

наш взгляд на вопросАрхитектура VIPER

VIPER. Наш взгляд на вопрос

Поддержка проекта без архитектуры

VIPER. Наш взгляд на вопрос

• TDD• Code review• ???

Процесс разработки

VIPER. Наш взгляд на вопрос

MVCController

Model View

VIPER. Наш взгляд на вопрос

MVVM

ViewController ViewModel Model

VIPER. Наш взгляд на вопрос

Presenter Data Store(Entity)View Interactor

VIPERRouter

VIPER. Наш взгляд на вопрос

Что же такое «модуль»?

VIPER. Наш взгляд на вопрос

Что же такое «модуль»?

VIPER. Наш взгляд на вопрос

Что же такое «модуль»?

VIPER. Наш взгляд на вопрос

class, NSObject

UIViewController

class,NSObject

class,NSObject

NSManagedObjectNSObject,struct

View Presenter Interactor Data Store(Entity)

Router

VIPER

VIPER. Наш взгляд на вопрос

Конфигурация модуля

VIPER. Наш взгляд на вопрос

Запуск конфигурации модуля

class MoviesListModuleInitializer: NSObject {

override func awakeFromNib() {

let configurator = factory.moduleConfigurator() configurator.configureModule(self.viewController) }}

VIPER. Наш взгляд на вопрос

Конфигурацияclass MoviesListModuleConfigurator { func configureModule(viewController: ViewController) {

let presenter = Presenter() let service = ServiceDefault()

… viewController.presenter = presenter presenter.builder = builder

… }}

VIPER. Наш взгляд на вопрос

let controller = UIViewController(data: data)let controller = UIViewController()controller.data = data

Проблема: Не хотим отказываться от Segue

Передача данных между модулями

VIPER. Наш взгляд на вопрос

Есть же метод

prepareForSegue

VIPER. Наш взгляд на вопрос

class BaseViewController: UIViewController, ModuleDataTransferProtocol {

func performSegueWithIdentifier(identifier: String, configurationBlock: (destination: ConfigurableController) -> Void) {

… } func prepareForSegue(segue: UIStoryboardSegue,

sender: AnyObject?) {

var destination = segue.destinationViewController block(destination: destination) }}

Базовый контроллер

VIPER. Наш взгляд на вопрос

Открытие модуля func openMovieWithId(movieId: String) {

controller.performSegueWith(block: { destinationController in

destinationController.configureModule(movieId) })

}

VIPER. Наш взгляд на вопрос

Схема передачи данныхrouter.openMoviewWithId(id)

vC.performSegueWithBlock(…)

prepareForSegue(…)

configurationBlock(destination)

VIPER. Наш взгляд на вопрос

Дополнительные соглашения

• NSManagedObject не дальше интерактора• Service Oriented Architecture (SOA) за интерактором• Общие части в pod’ы

VIPER. Наш взгляд на вопрос

Пример экранаVIPER + Swift

VIPER. Наш взгляд на вопрос

Пример модуля

VIPER. Наш взгляд на вопрос

Viewprotocol MoviesListViewInput: class {

func showData(dataStructure: DataStructure)

func showError(error: NSError)

func showEmptyView()}

VIPER. Наш взгляд на вопрос

Presenter// Данные от вьюшкиprotocol MoviesListViewOutput {

func viewIsReadyToAppear()

func didSelectMovieWithIndex(index: Int)}

// Данные от интерактораprotocol MoviesListInteractorOutput: class {

func didObtainMoviesList(movies: [Movie]?)

func didFailToObtainMoviesListWithError(error: NSError)}

VIPER. Наш взгляд на вопрос

Interactor

//Получение данных для модуляprotocol MoviesListInteractorInput {

func obtainMoviesList()

}

VIPER. Наш взгляд на вопрос

Router// Открытие другого экранаprotocol MoviesListRouterInput {

func openMovieWithId(movieId: String)}

VIPER. Наш взгляд на вопрос

Конкретнее

View

Presenter

Interactor

Service

viewIsReadyToAppear()

obtainData()

fetchData()

VIPER. Наш взгляд на вопрос

Все идет хорошоService

Interactor

Presenter

completionBlock()Array <Objects>

didObtainData()Array <Objects>

VIPER. Наш взгляд на вопрос

Отображаем данные

Presenter

View

showData()

VIPER. Наш взгляд на вопрос

Все идет плохо

Service

Interactor

Presenter

View

completionBlock()Error

didFailWithError()

showError()

VIPER. Наш взгляд на вопрос

Пример экранаVIPER + Swift

VIPER. Наш взгляд на вопрос

Viewprotocol WriteUsViewInput: class {

func showEmailError()

func clearInputViews()

func showSpinner()

func hideSpinner() }

VIPER. Наш взгляд на вопрос

Presenterprotocol WriteUsOutput: class {

func userRequestToWriteUs(withName name: String, email: String, message: String)

func userWantsToGoBack(areFieldsEmpty: Bool)}

protocol WriteUsInteractorOutput: class { func didSendFeedbackMessage() func didFailToSendFeedbackMessage(error: NSError)}

VIPER. Наш взгляд на вопрос

Interactorprotocol WriteUsInteractorInput {

func isValidEmail(email: String) -> Bool

func sendMessage(fromAuthor username: String, email: String, message: String)

}

VIPER. Наш взгляд на вопрос

Routerprotocol WriteUsRouterInput: class {

func goBackFromViewController(viewController: UIViewController)

func showAlertExitSubmitAlert(actionHandler: AlertActionsHandler)

func showAlertFeedbackSendDidSucceed()

func showAlertFeedbackSendDidFail()}

VIPER. Наш взгляд на вопрос

Конкретнее

View

Presenter

Interactor

userRequestToWriteUs()

isValidEmail()

VIPER. Наш взгляд на вопрос

Все идет хорошоPresenter

Interactor

Service

sendMessage()

sendMessage()

VIPER. Наш взгляд на вопрос

Отображаем данные

Presenter

Router

showFeedbackSucceed()

VIPER. Наш взгляд на вопрос

Ввод не валиден Presenter

View

showEmailError()

VIPER. Наш взгляд на вопрос

Что получается

Presenter ServiceView Interactor

Router Local storage

Networkclient

VIPER. Наш взгляд на вопрос

Достоинства• Быстрый вход в новый проект• Приемлемый код даже у новичков• Легкое переиспользование созданных компонент• Легкая модификация/поддержка кода

VIPER. Наш взгляд на вопрос

Недостатки• Большое количество времени• Большое количество кода• Большое количество интеграционных тестов• Холивары на тему «Где должен быть такой-то код?»

VIPER. Наш взгляд на вопрос

А нужен ли VIPER?/// Контролер для отображения информации о

приложенииclass AboutViewController: UIViewController {

//Текст текущей версии приложения @IBOutlet weak var versionLabel: UILabel! override func viewDidLoad() { super.viewDidLoad() let versionNumber = NSBundle.mainBundle().objectForInfoDictionaryKey("CFBundleShortVersionString") let buildNumber = NSBundle.mainBundle().objectForInfoDictionaryKey("CFBundleVersion") versionLabel.text = "Версия \(versionNumber!) (\(buildNumber!))" }

/** Метод для открытия нашей странички в iTunes */ @IBAction func openAppstore(sender: AnyObject) { UIApplication.sharedApplication().openURL(NSURL(string: "https://itunes.apple.com/ru/app/lenta.ru-vse-novosti-dna-politika/id975805914?mt=8")!) }}

VIPER. Наш взгляд на вопрос

Выводы

• Длинные по времени проекты

• Необходимость подключения новых людей в середине проекта

Стоит использовать Не стоит использовать

• Рекламное приложение/визитка/прототипирование

• Стартап, когда нужно выпустить MVP как можно быстрее

VIPER. Наш взгляд на вопрос

Open Source• Рамблер.Конференции — приложение• Generamba —  генератор• VIPER McFlurry —  библиотека• The Book of VIPER — сборник статей

https://github.com/rambler-ios

VIPER. Наш взгляд на вопрос

THANKS!