Diese Präsentation wurde erfolgreich gemeldet.
Die SlideShare-Präsentation wird heruntergeladen. ×

Rambler.iOS #5: VIPER и Swift

Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
SWIFT + VIPER
Что изменилось с переходом на Swift

YouTube-Videos werden auf SlideShare nicht mehr unterstützt.

Original auf YouTube ansehen

• Структура модуля
• Конфигурация модуля
• PONSO -> POSO
• Переходы между модулями
• Тестирование
• Общие впечатления

Hier ansehen

1 von 41 Anzeige

Rambler.iOS #5: VIPER и Swift

Herunterladen, um offline zu lesen

Rambler.iOS #5: VIPER и Swift (Попов Валерий).

Rambler.iOS - митапы iOS-разработчиков, организуемые компанией RAMBLER&Co.

Rambler.iOS #5: VIPER и Swift (Попов Валерий).

Rambler.iOS - митапы iOS-разработчиков, организуемые компанией RAMBLER&Co.

Anzeige
Anzeige

Weitere Verwandte Inhalte

Diashows für Sie (20)

Andere mochten auch (20)

Anzeige

Ähnlich wie Rambler.iOS #5: VIPER и Swift (20)

Weitere von RAMBLER&Co (20)

Anzeige

Aktuellste (20)

Rambler.iOS #5: VIPER и Swift

  1. 1. SWIFT + VIPER Что изменилось с переходом на Swift
  2. 2. • Структура модуля • Конфигурация модуля • PONSO -> POSO • Переходы между модулями • Тестирование • Общие впечатления
  3. 3. Структура модуля
  4. 4. Структура модуля: MFVIPEMPERVVM View: ViewInput Presenter:ViewOutput, ModuleInput Interactor: InteractorInput Router: RouterInput router output view interactor output Router Promise Reactive Interactor View Model Future View Presentation Model Wireframe Passive View Passive View Assembly
  5. 5. Структура модуля View (ViewInput) Presenter
 (ViewOutput, ModuleInput) Interactor (InteractorInput) Router
 (RouterInput) router output view interactor output Service Service Service Entity Entity
  6. 6. Структура модуля View Presenter Interactor Router Service Service Service Entity Entity NSObject Pure Swift
  7. 7. Структура модуля protocol TodayWeatherInteractorOutput: class { func setCurrentWeather(currentWeather: WeatherItem) } •Разделять протоколы по файлам •Не забывать :class для weak ссылок
  8. 8. Структура модуля class TodayWeatherPresenter: TodayWeatherModuleInput, TodayWeatherViewOutput { //MARK: TodayWeatherModuleInput //MARK: TodayWeatherViewOutput } •Ошибка: Declarations from extensions cannot be overriden yet •Нарушается целостность кода
  9. 9. Структура модуля class TodayWeatherPresenter: TodayWeatherModuleInput, TodayWeatherViewOutput { weak var view: TodayWeatherViewInput! var interactor: TodayWeatherInteractorInput! var router: TodayWeatherRouterInput! } •Корректную конфигурацию проверять в тестах
  10. 10. Структура модуля Generamba
  11. 11. Конфигурация модуля
  12. 12. Конфигурация модуля: Typhoon class TodayWeatherAssembly: TyphoonAssembly { enum ViperSel: Selector { case view = "view" case router = "router" //... } dynamic func presenter() -> AnyObject { return TyphoonDefinition.withClass (TodayWeatherPresenter.self) { (definition) in definition.injectProperty(ViperSel.router, with: self.router()) definition.injectProperty(ViperSel.view, with: self.view()) } } //... }
  13. 13. Конфигурация модуля: Typhoon typealias WeatherItem = (String, Int) @objc protocol TodayWeatherInteractorInput { func getWeatherData() -> WeatherItem } method cannot be marked @objc because ... cannot be represented in Objective-C Получаем ошибку:
  14. 14. Конфигурация модуля: Swift DI frameworks Swinject let container = Container() container.register(TodayWeatherRouterInput.self) { _ in TodayWeatherRouter() } container.register(TodayWeatherViewOutput.self) { registrator in TodayWeatherPresenter(router: registrator.resolve(TodayWeatherRouterInput.self)!) } //Configurator let presenter = container.resolve(TodayWeatherRouterInput.self)
  15. 15. Конфигурация модуля: Swift DI frameworks Dip let dependencyContainer = DependencyContainer() { container in container.register { TodayWeatherRouter() as TodayWeatherRouterInput } container.register { TodayWeatherPresenter(router: try! container.resolve() as TodayWeatherRouterInput) as TodayWeatherViewOutput } } //Configurator let router = try! dependencyContainer.resolve() as TodayWeatherRouter
  16. 16. Swift DI frameworks: Проблемы •Существующие решения - Service locators •Runtime возможности только для NSObject наследников •Readonly Reflection API
  17. 17. Конфигурация модуля: Storyboard DI class TodayWeatherModuleInitializer: NSObject { @IBOutlet weak var viewController: TodayWeatherViewController! override func awakeFromNib() { let configurator = TodayWeatherModuleConfigurator() configurator. configureModuleForViewInput(viewController) } }
  18. 18. Конфигурация модуля: Конфигуратор class TodayWeatherModuleConfigurator: BaseModuleConfiguratorProtocol { func configureModuleForViewInput<UIViewController> (viewInput: UIViewController) { if let todayWeatherController = viewInput as? TodayWeatherViewController { configure(todayWeatherController) } } //... }
  19. 19. Конфигурация модуля: Конфигуратор private func configure(viewController: TodayWeatherViewController) { let router = TodayWeatherRouter() router.viewController = viewController let presenter = TodayWeatherPresenter() presenter.view = viewController presenter.router = router let interactor = TodayWeatherInteractor() interactor.output = presenter presenter.interactor = interactor viewController.output = presenter }
  20. 20. Структура модуля View (ViewController) Presenter Interactor Router Service Service Service Entity Entity Configurator Initializer Storyboard
  21. 21. PONSO -> POSO
  22. 22. PONSO -> POSO @interface DayWeather : NSObject @property (readonly) NSString *weather; @property (readonly) NSString *temperature; @property (readonly) NSString *temperatureIcon; - (instancetype)initWithWeather:(NSString *)weather temperature:(NSString *)temperature temperatureIcon:(NSString *)icon; + (instancetype)weatherWithWeather:(NSString *)weather temperature:(NSString *)temperature temperatureIcon:(NSString *)icon; @end
  23. 23. enum TimeOfDay: String { case Now = "now" case Morning = "morning" case Afternoon = "afternoon" case Evening = "evening" case Night = "night" } struct WeatherItem { let timeOfDay: TimeOfDay? let weather: String? let temperature: String? let temperatureIconName: String? } PONSO -> POSO
  24. 24. PONSO -> POSO •Immutability, thread safe из коробки •struct и enum поддерживают большинство возможностей классов •Оптимизации
  25. 25. Переходы между модулями
  26. 26. Переходы между модулями Swizzling ?
  27. 27. Переходы между модулями Protocol Extensions
  28. 28. Переходы между модулями: Transition Handler protocol ViperModuleTransitionHandler: class { func openModule(segueIdentifier: String, configurationBlock: ConfigurationBlock) func closeModule() }
  29. 29. extension ViperModuleTransitionHandler where Self: UIViewController { func openModule(segueIdentifier:String, block:ConfigurationBlock) { let segueInfo = SegueInfo() segueInfo.configurationBlock = block performSegueWithIdentifier(segueIdentifier, sender: segueInfo) }
 } Переходы между модулями: Transition Handler
  30. 30. Переходы между модулями: Module View override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject?) { guard let configurationHolder = segue.destinationViewController else {return} configurationBlock(configurationHolder.moduleInput) }
  31. 31. Тестирование
  32. 32. Тестирование OCMock OCMProtocolMock OCMClassMock OCMVerify OCMStub
  33. 33. Тестирование Spy Stub Mock Писать моки самому не сложно
  34. 34. Тестирование: Mocking func testConfigureWithWeatherId() { //given let presenter = TodayWeatherPresenter() let interactor = MockInteractorInput() presenter.interactor = interactor //when presenter.configureViewForWeatherId("testWeatherId") //then XCTAssertTrue(interactor.didCallObtain) XCTAssertEqual("testOfferId", interactor.offerId) }
  35. 35. Тестирование: Mocking class MockInteractorInput : TodayWeatherInteractorInput { var didCallObtain = false var weatherId : String! func obtainWeatherById(weatherId: String) { didCallObtain = true self.weatherId = weatherId } }
  36. 36. Тестирование PRIVATE INTERNAL PUBLIC @testable
  37. 37. В результате ?
  38. 38. Зачем переходить на Swift • Меньше файлов, выразительный синтаксис • Модификаторы доступа, пространства имен • Строгая типизация и явный nil • Immutability из коробки • Мультипарадигменность
  39. 39. Viper+ Swift • Революции не случилось • Модули пишутся быстрее • Можно эффективно использовать возможности языка • Тесты пишутся медленнее
  40. 40. Спасибо за внимание

×