SlideShare a Scribd company logo
MVVM в реальных 
проектах 
Юрий Буянов 
“Одноклассники”
MVVM
MVC
“Massive View Controller” 
• Занимается вообще всем 
• Сильная связанность с View layer 
• Трудно тестировать 
• Трудно переиспользовать
Model-View-ViewModel 
View 
(+ViewController) Lightweight View 
ViewModel 
Model 
UI logic 
Business logic
Model-View-ViewModel 
View 
(+ViewController) Lightweight View 
ViewModel 
Model 
UI logic 
Business logic 
Bindings!
ViewModel 
• Не знает ничего про ViewController 
• Не использует UIKit 
• Отображает (?) состояние UI с помощью KVO- 
совместимых свойств или RAC-сигналов 
• Действия представлены в виде методов или RAC- 
команд 
• Легко тестируема (и должна тестироваться)
View 
(ViewController) 
• Декларативно привязывает состояние UI к 
состоянию VM 
• Обрабатывает чистую логику UI (вёрстка, 
анимации, ориентирование) 
• Может зависеть от нескольких ViewModel
Биндинги 
- (void)viewDidLoad 
{ 
[super viewDidLoad]; 
RAC(self.trackTitleLabel, text) = RACObserve(self.viewModel, trackTitle); 
RAC(self.playBtn, enabled) = RACObserve(self.viewModel, loading).not; 
} 
- (IBAction)nextBtnTap:(id)sender { 
[self.viewModel nextBtnPressed]; 
}
View 
UI customization 
layout 
animations 
orientation changes 
ViewModel 
Model interaction (network, 
storage) 
Model-related UI state 
??? 
Navigation 
Image Loading 
Action Confirmations 
UI-only actions 
…
Навигация
Ad hoc 
UINavigationController 
Sections 
Controller 
Talks 
Controller 
ctrl = [[TalksController alloc] init] 
2 push 
1 инициализация
@implementation SectionsController 
- (IBAction)mobileBtnTap:(id)sender { 
UIViewController *ctrl = [[TalksController alloc] init]; 
[self.navigationController pushViewController:ctrl animated:YES]; 
} 
@end
Ненужная связанность (coupling) 
@implementation SectionsController 
- (IBAction)mobileBtnTap:(id)sender { 
UIViewController *ctrl = [[TalksController alloc] init]; 
[self.navigationController pushViewController:ctrl animated:YES]; 
} 
@end
Ad Hoc + MVVM 
UINavigationController 
Sections 
Controller 
Talks Controller 
4 push 
2 
создаёт 
Sections 
ViewModel 
Talks 
ViewModel 
1 действие 
создаёт 
3
@implementation SectionsViewModel 
- (void)mobileBtnPressed { 
MobileTalksViewModel *vm = [[MobileTalksViewModel alloc] init]; 
UIViewController *ctrl = [[TalksController alloc] initWithVM:vm]; 
[self.navigationController pushViewController:ctrl animated:YES]; 
} 
@end
@implementation SectionsViewModel 
- (void)mobileBtnPressed { 
MobileTalksViewModel *vm = [[MobileTalksViewModel alloc] init]; 
UIViewController *ctrl = [[TalksController alloc] initWithVM:vm]; 
[self.navigationController pushViewController:ctrl animated:YES]; 
} 
@end 
Ненужная связанность 
UI-код внутри ViewModel! :(
Решение “В лоб” 
UINavigationController 
Sections 
Controller 
Sections 2 создаёт 
ViewModel 
Talks 
ViewModel 
1 действие
Решение “В лоб” 
UINavigationController 
Sections 
Controller 
Sections 2 создаёт 
ViewModel 
Talks 
ViewModel 
1 действие 
3 сигнал
Решение “В лоб” 
UINavigationController 
Sections 
Controller 
Talks Controller 
Sections 2 создаёт 
ViewModel 
Talks 
ViewModel 
1 действие 
3 сигнал 
4 
создаёт и 
связывает
Решение “В лоб” 
UINavigationController 
Sections 
Controller 
Talks Controller 
5 push 
Sections 2 создаёт 
ViewModel 
Talks 
ViewModel 
1 действие 
3 сигнал 
4 
создаёт и 
связывает
@implementation SectionsViewModel 
- (void)mobileBtnPressed { 
MobileTalksViewModel *vm = [[MobileTalksViewModel alloc] init]; 
[_talksViewModelsSubject sendNext:vm]; 
} 
@end
@implementation SectionsController 
- (IBAction)mobileBtnTap:(id)sender { 
[self.viewModel mobileBtnPressed]; 
} 
- (void)viewDidLoad { 
[self.viewModel.talksViewModelsSignal 
subscribeNext:^(id viewModel) { 
UIViewController* ctrl = [[TalksController alloc] initWithVM:viewModel]; 
[self.navigationController pushViewController:ctrl animated:YES]; 
}]; 
} 
@end
Решение “В лоб” 
• Большая степень связанности в VM и 
контроллере 
• Негибкость 
• Повторение кода 
• Отдельный сигнал для каждого “маршрута”
Роутер 
(Navigation Object)
MVVM + Роутер 
UINavigationController 
Sections 
Controller 
1 action 2 showTalks 
Sections 
ViewModel
MVC + Роутер 
UINavigationController 
Sections 
Controller 
showDst
Роутер 
• Имеет доступ к навигационным контроллерам (navigation 
controller, tab controller, drawer controller, menu controller) 
• Создаёт и конфигурирует экземпляры VM и контроллеров 
• (сам или используя DI-контейнер) 
• Осуществляет переходы между экранами 
• Mockable 
• Отлично работает в рамках MVVM и MVC
Роутер 
@interface Router : NSObject 
- (void)showMobileTalks; 
- (void)showWebTalks; 
- (void)showGamesTalks; 
- (void)showTalk:(Talk*)talk; 
@end
Роутер 
@implementation Router 
- (void)showMobileTalks { 
MobileTalksViewModel *vm = [[MobileTalksViewModel alloc] init]; 
UIViewController *ctrl = [[TalksController alloc] initWithVM:vm]; 
[self.mainNavigationController pushViewController:ctrl animated:YES]; 
} 
@end
@implementation SectionsController 
- (IBAction)mobileBtnTap:(id)sender { 
[self.viewModel mobileBtnPressed]; 
} 
- (void)viewDidLoad { 
[self.viewModel.talksViewModelsSignal 
subscribeNext:^(id viewModel) { 
UIViewController* ctrl = [[TalksController alloc] initWithVM:viewModel]; 
[self.navigationController pushViewController:ctrl animated:YES]; 
}]; 
} 
@end
@implementation SectionsViewModel 
- (void)mobileBtnPressed { 
[self.router showMobileTalks]; 
} 
@end
Вложенные контроллеры 
UINavigationController 
Controller 
Child controller 
Some other controller 
ViewModel 
Child ViewModel 
Some other ViewModel
Вложенные контроллеры 
UINavigationController 
Controller 
Child controller 
Some other controller 
ViewModel 
Child ViewModel 
Some other ViewModel
Универсальные 
приложения
Частный случай: 
URL-based роутер 
[self.router showMobileTalks]; 
[self.router open:@"/sections/mobile" modal:NO];
URL-based роутер 
• Легко настраивается 
• Упрощает поддержку URL-схем 
• Упрощает переход от веб-приложений к нативным 
• Логика навигации может “утекать” в VM/контроллер 
• Сложности с передачей сложных объектов 
• Подходит не для всех приложений
Списки 
(UICollectionView, UITableView)
Модель ячейки 
ViewController ViewModel 
UICollectionView/UITableView 
Cell 
- (void)setViewModel:(MYCellViewModel *)viewModel 
CellViewModel 
CellViewModel 
CellViewModel 
CellViewModel 
- (void)viewDidLoad 
{ 
[super viewDidLoad]; 
[self.viewModel.updatedContentSignal 
subscribeNext:^(id x) { 
[self.collectionView reloadData]; 
}]; 
} 
Cell 
Cell 
@property RACSubject *updatedContentSignal; 
NSArray *cellViewModels
Статическая модель 
ячейки 
Cell 
- (void)setViewModel:(OKPTrackCellViewModel *)viewModel { 
NSParameterAssert(viewModel); 
self.titleLabel.text = viewModel.title; 
self.subTitleLabel.text = viewModel.subtitle; 
self.someIcon.hidden = !viewModel.someFlag; 
Cell ViewModel 
} 
@property NSString* title; 
@property NSString* subtitle; 
@property BOOL someFlag;
Динамическая модель 
ячейки 
Cell 
- (void)setViewModel:(OKPTrackCellViewModel *)viewModel { 
NSParameterAssert(viewModel); 
self.titleLabel.text = viewModel.title; 
self.subTitleLabel.text = viewModel.subtitle; 
self.someIcon.hidden = !viewModel.someFlag; 
Cell ViewModel 
} 
@property NSString* title; 
@property NSString* subtitle; 
@property BOOL someFlag; //Может изменяться!
Динамическая модель 
ячейки 
Cell 
RAC(self.someIcon, hidden) = RACObserve(viewModel.someFlag).not;
Warning: cell reuse 
Cell 
RAC(self.someIcon, hidden) = RACObserve(viewModel.someFlag).not; 
/// A given key on an object should only have one active signal bound to 
it at any given time. Binding more than one signal to the same property 
is considered undefined behavior.
Warning: cell reuse 
Cell 
RAC(self.someIcon, hidden) =[RACObserve(viewModel.someFlag).not 
takeUntil:self.rac_prepareForReuseSignal]; 
/// Solution: unsubscribe from RACObserve signal on cell reuse
Ощущения 
(на данном этапе) 
• Технология “на вырост” 
• Сделает возможным написание тестов, но не 
напишет их за вас 
• Хинт: используйте Dependency Injection. 
• Вам придётся полюбить ReactiveCocoa
Спасибо

More Related Content

What's hot

Introduction to React
Introduction to ReactIntroduction to React
Introduction to React
Лагуновский Иван
 
Особенности разработки API / Всеволод Шмыров (Яндекс)
Особенности разработки API / Всеволод Шмыров (Яндекс)Особенности разработки API / Всеволод Шмыров (Яндекс)
Особенности разработки API / Всеволод Шмыров (Яндекс)
Ontico
 
сервисы в Angular js
сервисы в Angular jsсервисы в Angular js
сервисы в Angular js
yakimchuk
 
MWWM
MWWMMWWM
MWWM
Cleveroad
 
Пользователь точно оценит! Повышение производительности мобильных приложений ...
Пользователь точно оценит! Повышение производительности мобильных приложений ...Пользователь точно оценит! Повышение производительности мобильных приложений ...
Пользователь точно оценит! Повышение производительности мобильных приложений ...
Ontico
 
Тестируй это / Виктор Русакович (GP Solutions)
Тестируй это / Виктор Русакович (GP Solutions)Тестируй это / Виктор Русакович (GP Solutions)
Тестируй это / Виктор Русакович (GP Solutions)
Ontico
 
Angular 2: Всех переиграл
Angular 2: Всех переигралAngular 2: Всех переиграл
Angular 2: Всех переиграл
Eugene Zharkov
 
занятие 2
занятие 2занятие 2
занятие 2ajantis
 
Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы
Rambler.iOS #4: Создание модульных приложений на примере Рамблер.КассыRambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы
Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы
RAMBLER&Co
 
ASP.NET MVC 3 Anton Vidishchev
ASP.NET MVC 3 Anton VidishchevASP.NET MVC 3 Anton Vidishchev
ASP.NET MVC 3 Anton Vidishchev
Alex Tumanoff
 
C# Web. Занятие 02.
C# Web. Занятие 02.C# Web. Занятие 02.
C# Web. Занятие 02.
Igor Shkulipa
 
презентация вводного доклада Angular на fronttalks.ru
презентация вводного доклада Angular на fronttalks.ruпрезентация вводного доклада Angular на fronttalks.ru
презентация вводного доклада Angular на fronttalks.ru
Ivan Gromov
 
Лучший frontend-фреймворк, и почему вы его не хотите
Лучший frontend-фреймворк, и почему вы его не хотитеЛучший frontend-фреймворк, и почему вы его не хотите
Лучший frontend-фреймворк, и почему вы его не хотите
CodeFest
 
Rambler.iOS #5: Генерамба и прочие аспекты кодогенерации в VIPER
Rambler.iOS #5: Генерамба и прочие аспекты кодогенерации в VIPERRambler.iOS #5: Генерамба и прочие аспекты кодогенерации в VIPER
Rambler.iOS #5: Генерамба и прочие аспекты кодогенерации в VIPER
RAMBLER&Co
 
Viper architecture
Viper architectureViper architecture
Viper architecture
Katerina Korovkina
 
131 - Spring. Переход между страницами
131 -  Spring. Переход между страницами 131 -  Spring. Переход между страницами
131 - Spring. Переход между страницами
Roman Brovko
 
Lift, play, akka, rails part1
Lift, play, akka, rails part1Lift, play, akka, rails part1
Lift, play, akka, rails part1Eduard Antsupov
 
Фреймворк Slot, Good Parts, Александр Бирюков
Фреймворк Slot, Good Parts, Александр БирюковФреймворк Slot, Good Parts, Александр Бирюков
Фреймворк Slot, Good Parts, Александр Бирюков
DevDay
 
130 - Spring WebFlow. Создание проекта
130 - Spring WebFlow. Создание проекта130 - Spring WebFlow. Создание проекта
130 - Spring WebFlow. Создание проекта
Roman Brovko
 
Анджей Гужовский "Riot.JS, или как приготовить современные Web Components"
Анджей Гужовский "Riot.JS, или как приготовить современные Web Components"Анджей Гужовский "Riot.JS, или как приготовить современные Web Components"
Анджей Гужовский "Riot.JS, или как приготовить современные Web Components"
Fwdays
 

What's hot (20)

Introduction to React
Introduction to ReactIntroduction to React
Introduction to React
 
Особенности разработки API / Всеволод Шмыров (Яндекс)
Особенности разработки API / Всеволод Шмыров (Яндекс)Особенности разработки API / Всеволод Шмыров (Яндекс)
Особенности разработки API / Всеволод Шмыров (Яндекс)
 
сервисы в Angular js
сервисы в Angular jsсервисы в Angular js
сервисы в Angular js
 
MWWM
MWWMMWWM
MWWM
 
Пользователь точно оценит! Повышение производительности мобильных приложений ...
Пользователь точно оценит! Повышение производительности мобильных приложений ...Пользователь точно оценит! Повышение производительности мобильных приложений ...
Пользователь точно оценит! Повышение производительности мобильных приложений ...
 
Тестируй это / Виктор Русакович (GP Solutions)
Тестируй это / Виктор Русакович (GP Solutions)Тестируй это / Виктор Русакович (GP Solutions)
Тестируй это / Виктор Русакович (GP Solutions)
 
Angular 2: Всех переиграл
Angular 2: Всех переигралAngular 2: Всех переиграл
Angular 2: Всех переиграл
 
занятие 2
занятие 2занятие 2
занятие 2
 
Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы
Rambler.iOS #4: Создание модульных приложений на примере Рамблер.КассыRambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы
Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы
 
ASP.NET MVC 3 Anton Vidishchev
ASP.NET MVC 3 Anton VidishchevASP.NET MVC 3 Anton Vidishchev
ASP.NET MVC 3 Anton Vidishchev
 
C# Web. Занятие 02.
C# Web. Занятие 02.C# Web. Занятие 02.
C# Web. Занятие 02.
 
презентация вводного доклада Angular на fronttalks.ru
презентация вводного доклада Angular на fronttalks.ruпрезентация вводного доклада Angular на fronttalks.ru
презентация вводного доклада Angular на fronttalks.ru
 
Лучший frontend-фреймворк, и почему вы его не хотите
Лучший frontend-фреймворк, и почему вы его не хотитеЛучший frontend-фреймворк, и почему вы его не хотите
Лучший frontend-фреймворк, и почему вы его не хотите
 
Rambler.iOS #5: Генерамба и прочие аспекты кодогенерации в VIPER
Rambler.iOS #5: Генерамба и прочие аспекты кодогенерации в VIPERRambler.iOS #5: Генерамба и прочие аспекты кодогенерации в VIPER
Rambler.iOS #5: Генерамба и прочие аспекты кодогенерации в VIPER
 
Viper architecture
Viper architectureViper architecture
Viper architecture
 
131 - Spring. Переход между страницами
131 -  Spring. Переход между страницами 131 -  Spring. Переход между страницами
131 - Spring. Переход между страницами
 
Lift, play, akka, rails part1
Lift, play, akka, rails part1Lift, play, akka, rails part1
Lift, play, akka, rails part1
 
Фреймворк Slot, Good Parts, Александр Бирюков
Фреймворк Slot, Good Parts, Александр БирюковФреймворк Slot, Good Parts, Александр Бирюков
Фреймворк Slot, Good Parts, Александр Бирюков
 
130 - Spring WebFlow. Создание проекта
130 - Spring WebFlow. Создание проекта130 - Spring WebFlow. Создание проекта
130 - Spring WebFlow. Создание проекта
 
Анджей Гужовский "Riot.JS, или как приготовить современные Web Components"
Анджей Гужовский "Riot.JS, или как приготовить современные Web Components"Анджей Гужовский "Riot.JS, или как приготовить современные Web Components"
Анджей Гужовский "Riot.JS, или как приготовить современные Web Components"
 

Similar to #MBLTdev: Опыт использования MVVM в реальных проектах

2016-08-20 02 Антон Ковалев, Антон Кормаков. Viper. Чистая архитектура для iOS
2016-08-20 02 Антон Ковалев, Антон Кормаков. Viper. Чистая архитектура для iOS2016-08-20 02 Антон Ковалев, Антон Кормаков. Viper. Чистая архитектура для iOS
2016-08-20 02 Антон Ковалев, Антон Кормаков. Viper. Чистая архитектура для iOS
Омские ИТ-субботники
 
iOS-05_2-UIKit
iOS-05_2-UIKitiOS-05_2-UIKit
iOS-05_2-UIKit
Noveo
 
Viper - чистая архитектура iOS-приложения (И. Чирков)
Viper - чистая архитектура iOS-приложения (И. Чирков)Viper - чистая архитектура iOS-приложения (И. Чирков)
Viper - чистая архитектура iOS-приложения (И. Чирков)
65apps
 
Интуит. Разработка приложений для iOS. Лекция 5. Сложные Views
Интуит. Разработка приложений для iOS. Лекция 5. Сложные ViewsИнтуит. Разработка приложений для iOS. Лекция 5. Сложные Views
Интуит. Разработка приложений для iOS. Лекция 5. Сложные ViewsГлеб Тарасов
 
Антон Валюх - Использование паттерна Mvvm в android
Антон Валюх - Использование паттерна Mvvm в androidАнтон Валюх - Использование паттерна Mvvm в android
Антон Валюх - Использование паттерна Mvvm в android
DataArt
 
Референсная архитектура приложения на ASP.NET MVC
Референсная архитектура приложения на ASP.NET MVCРеференсная архитектура приложения на ASP.NET MVC
Референсная архитектура приложения на ASP.NET MVCAndrew Mayorov
 
Школа-Студия разработки приложений для iOS. 5 лекция. Разное
Школа-Студия разработки приложений для iOS. 5 лекция. РазноеШкола-Студия разработки приложений для iOS. 5 лекция. Разное
Школа-Студия разработки приложений для iOS. 5 лекция. РазноеГлеб Тарасов
 
CocoaHeads Moscow. Владислав Дугнист. «Dependency Injection с Blood Magic»
CocoaHeads Moscow. Владислав Дугнист. «Dependency Injection с Blood Magic»CocoaHeads Moscow. Владислав Дугнист. «Dependency Injection с Blood Magic»
CocoaHeads Moscow. Владислав Дугнист. «Dependency Injection с Blood Magic»
Mail.ru Group
 
Разработка WPF приложений в стиле ViewModel First
Разработка WPF приложений в стиле ViewModel FirstРазработка WPF приложений в стиле ViewModel First
Разработка WPF приложений в стиле ViewModel First
Denis Tsvettsih
 
AndroidMVPHelper
AndroidMVPHelperAndroidMVPHelper
AndroidMVPHelper
DataArt
 
Школа-Студия разработки приложений для iOS. 3 лекция. Интерфейсы, прололжение
Школа-Студия разработки приложений для iOS. 3 лекция. Интерфейсы, прололжениеШкола-Студия разработки приложений для iOS. 3 лекция. Интерфейсы, прололжение
Школа-Студия разработки приложений для iOS. 3 лекция. Интерфейсы, прололжениеГлеб Тарасов
 
Объять необъятное, или как использовать несколько MVVM фреймворков в одном XA...
Объять необъятное, или как использовать несколько MVVM фреймворков в одном XA...Объять необъятное, или как использовать несколько MVVM фреймворков в одном XA...
Объять необъятное, или как использовать несколько MVVM фреймворков в одном XA...
Denis Tsvettsih
 
Yet another architectur. Как устроены приложения SuperJob изнутри
Yet another architectur.  Как устроены приложения SuperJob изнутриYet another architectur.  Как устроены приложения SuperJob изнутри
Yet another architectur. Как устроены приложения SuperJob изнутри
Denisenko Sergei
 
Паттерны проектирования
Паттерны проектированияПаттерны проектирования
Паттерны проектирования
ITCP Community
 
Всеволод Шмыров, Яндекс
Всеволод Шмыров, ЯндексВсеволод Шмыров, Яндекс
Всеволод Шмыров, Яндекс
Elena Voynova
 
Mvc, mvp and mvvm: A comparison of architectural patterns
Mvc, mvp and mvvm: A comparison of architectural patternsMvc, mvp and mvvm: A comparison of architectural patterns
Mvc, mvp and mvvm: A comparison of architectural patterns
Ivan Dyachenko
 
MVVM в WinForms – DevExpress Way (теория и практика)
MVVM в WinForms – DevExpress Way (теория и практика)MVVM в WinForms – DevExpress Way (теория и практика)
MVVM в WinForms – DevExpress Way (теория и практика)
GoSharp
 
MVP, Moxy. Как правильно пользоваться
MVP, Moxy. Как правильно пользоватьсяMVP, Moxy. Как правильно пользоваться
MVP, Moxy. Как правильно пользоваться
Yuri Shmakov
 
ASP.NET MVC: new era?
ASP.NET MVC: new era?ASP.NET MVC: new era?
ASP.NET MVC: new era?
Alexander Konduforov
 

Similar to #MBLTdev: Опыт использования MVVM в реальных проектах (20)

2016-08-20 02 Антон Ковалев, Антон Кормаков. Viper. Чистая архитектура для iOS
2016-08-20 02 Антон Ковалев, Антон Кормаков. Viper. Чистая архитектура для iOS2016-08-20 02 Антон Ковалев, Антон Кормаков. Viper. Чистая архитектура для iOS
2016-08-20 02 Антон Ковалев, Антон Кормаков. Viper. Чистая архитектура для iOS
 
iOS-05_2-UIKit
iOS-05_2-UIKitiOS-05_2-UIKit
iOS-05_2-UIKit
 
Viper - чистая архитектура iOS-приложения (И. Чирков)
Viper - чистая архитектура iOS-приложения (И. Чирков)Viper - чистая архитектура iOS-приложения (И. Чирков)
Viper - чистая архитектура iOS-приложения (И. Чирков)
 
Интуит. Разработка приложений для iOS. Лекция 5. Сложные Views
Интуит. Разработка приложений для iOS. Лекция 5. Сложные ViewsИнтуит. Разработка приложений для iOS. Лекция 5. Сложные Views
Интуит. Разработка приложений для iOS. Лекция 5. Сложные Views
 
Антон Валюх - Использование паттерна Mvvm в android
Антон Валюх - Использование паттерна Mvvm в androidАнтон Валюх - Использование паттерна Mvvm в android
Антон Валюх - Использование паттерна Mvvm в android
 
Референсная архитектура приложения на ASP.NET MVC
Референсная архитектура приложения на ASP.NET MVCРеференсная архитектура приложения на ASP.NET MVC
Референсная архитектура приложения на ASP.NET MVC
 
Школа-Студия разработки приложений для iOS. 5 лекция. Разное
Школа-Студия разработки приложений для iOS. 5 лекция. РазноеШкола-Студия разработки приложений для iOS. 5 лекция. Разное
Школа-Студия разработки приложений для iOS. 5 лекция. Разное
 
CocoaHeads Moscow. Владислав Дугнист. «Dependency Injection с Blood Magic»
CocoaHeads Moscow. Владислав Дугнист. «Dependency Injection с Blood Magic»CocoaHeads Moscow. Владислав Дугнист. «Dependency Injection с Blood Magic»
CocoaHeads Moscow. Владислав Дугнист. «Dependency Injection с Blood Magic»
 
Разработка WPF приложений в стиле ViewModel First
Разработка WPF приложений в стиле ViewModel FirstРазработка WPF приложений в стиле ViewModel First
Разработка WPF приложений в стиле ViewModel First
 
AndroidMVPHelper
AndroidMVPHelperAndroidMVPHelper
AndroidMVPHelper
 
Школа-Студия разработки приложений для iOS. 3 лекция. Интерфейсы, прололжение
Школа-Студия разработки приложений для iOS. 3 лекция. Интерфейсы, прололжениеШкола-Студия разработки приложений для iOS. 3 лекция. Интерфейсы, прололжение
Школа-Студия разработки приложений для iOS. 3 лекция. Интерфейсы, прололжение
 
Объять необъятное, или как использовать несколько MVVM фреймворков в одном XA...
Объять необъятное, или как использовать несколько MVVM фреймворков в одном XA...Объять необъятное, или как использовать несколько MVVM фреймворков в одном XA...
Объять необъятное, или как использовать несколько MVVM фреймворков в одном XA...
 
Yet another architectur. Как устроены приложения SuperJob изнутри
Yet another architectur.  Как устроены приложения SuperJob изнутриYet another architectur.  Как устроены приложения SuperJob изнутри
Yet another architectur. Как устроены приложения SuperJob изнутри
 
Паттерны проектирования
Паттерны проектированияПаттерны проектирования
Паттерны проектирования
 
Всеволод Шмыров, Яндекс
Всеволод Шмыров, ЯндексВсеволод Шмыров, Яндекс
Всеволод Шмыров, Яндекс
 
Mvc, mvp and mvvm: A comparison of architectural patterns
Mvc, mvp and mvvm: A comparison of architectural patternsMvc, mvp and mvvm: A comparison of architectural patterns
Mvc, mvp and mvvm: A comparison of architectural patterns
 
MVVM в WinForms – DevExpress Way (теория и практика)
MVVM в WinForms – DevExpress Way (теория и практика)MVVM в WinForms – DevExpress Way (теория и практика)
MVVM в WinForms – DevExpress Way (теория и практика)
 
MVP, Moxy. Как правильно пользоваться
MVP, Moxy. Как правильно пользоватьсяMVP, Moxy. Как правильно пользоваться
MVP, Moxy. Как правильно пользоваться
 
Squeek School #7
Squeek School #7Squeek School #7
Squeek School #7
 
ASP.NET MVC: new era?
ASP.NET MVC: new era?ASP.NET MVC: new era?
ASP.NET MVC: new era?
 

More from e-Legion

MBLT16: Elena Rydkina, Pure
MBLT16: Elena Rydkina, PureMBLT16: Elena Rydkina, Pure
MBLT16: Elena Rydkina, Pure
e-Legion
 
MBLT16: Alexander Lukin, AppMetrica
MBLT16: Alexander Lukin, AppMetricaMBLT16: Alexander Lukin, AppMetrica
MBLT16: Alexander Lukin, AppMetrica
e-Legion
 
MBLT16: Vincent Wu, Alibaba Mobile
MBLT16: Vincent Wu, Alibaba MobileMBLT16: Vincent Wu, Alibaba Mobile
MBLT16: Vincent Wu, Alibaba Mobile
e-Legion
 
MBLT16: Dmitriy Geranin, Afisha Restorany
MBLT16: Dmitriy Geranin, Afisha RestoranyMBLT16: Dmitriy Geranin, Afisha Restorany
MBLT16: Dmitriy Geranin, Afisha Restorany
e-Legion
 
MBLT16: Marvin Liao, 500Startups
MBLT16: Marvin Liao, 500StartupsMBLT16: Marvin Liao, 500Startups
MBLT16: Marvin Liao, 500Startups
e-Legion
 
MBLT16: Andrey Maslak, Aviasales
MBLT16: Andrey Maslak, AviasalesMBLT16: Andrey Maslak, Aviasales
MBLT16: Andrey Maslak, Aviasales
e-Legion
 
MBLT16: Andrey Bakalenko, Sberbank Online
MBLT16: Andrey Bakalenko, Sberbank OnlineMBLT16: Andrey Bakalenko, Sberbank Online
MBLT16: Andrey Bakalenko, Sberbank Online
e-Legion
 
Rx Java architecture
Rx Java architectureRx Java architecture
Rx Java architecture
e-Legion
 
Rx java
Rx javaRx java
Rx java
e-Legion
 
MBLTDev15: Hector Zarate, Spotify
MBLTDev15: Hector Zarate, SpotifyMBLTDev15: Hector Zarate, Spotify
MBLTDev15: Hector Zarate, Spotify
e-Legion
 
MBLTDev15: Cesar Valiente, Wunderlist
MBLTDev15: Cesar Valiente, WunderlistMBLTDev15: Cesar Valiente, Wunderlist
MBLTDev15: Cesar Valiente, Wunderlist
e-Legion
 
MBLTDev15: Brigit Lyons, Soundcloud
MBLTDev15: Brigit Lyons, SoundcloudMBLTDev15: Brigit Lyons, Soundcloud
MBLTDev15: Brigit Lyons, Soundcloud
e-Legion
 
MBLTDev15: Egor Tolstoy, Rambler&Co
MBLTDev15: Egor Tolstoy, Rambler&CoMBLTDev15: Egor Tolstoy, Rambler&Co
MBLTDev15: Egor Tolstoy, Rambler&Co
e-Legion
 
MBLTDev15: Alexander Orlov, Postforpost
MBLTDev15: Alexander Orlov, PostforpostMBLTDev15: Alexander Orlov, Postforpost
MBLTDev15: Alexander Orlov, Postforpost
e-Legion
 
MBLTDev15: Artemiy Sobolev, Parallels
MBLTDev15: Artemiy Sobolev, ParallelsMBLTDev15: Artemiy Sobolev, Parallels
MBLTDev15: Artemiy Sobolev, Parallels
e-Legion
 
MBLTDev15: Alexander Dimchenko, DIT
MBLTDev15: Alexander Dimchenko, DITMBLTDev15: Alexander Dimchenko, DIT
MBLTDev15: Alexander Dimchenko, DIT
e-Legion
 
MBLTDev: Evgeny Lisovsky, Litres
MBLTDev: Evgeny Lisovsky, LitresMBLTDev: Evgeny Lisovsky, Litres
MBLTDev: Evgeny Lisovsky, Litres
e-Legion
 
MBLTDev: Alexander Dimchenko, Bright Box
MBLTDev: Alexander Dimchenko, Bright Box MBLTDev: Alexander Dimchenko, Bright Box
MBLTDev: Alexander Dimchenko, Bright Box
e-Legion
 
MBLTDev15: Konstantin Goldshtein, Microsoft
MBLTDev15: Konstantin Goldshtein, MicrosoftMBLTDev15: Konstantin Goldshtein, Microsoft
MBLTDev15: Konstantin Goldshtein, Microsoft
e-Legion
 
MBLTDev15: Anna Mikhina, Maxim Evdokimov, Tinkoff Bank
MBLTDev15: Anna Mikhina, Maxim Evdokimov, Tinkoff Bank MBLTDev15: Anna Mikhina, Maxim Evdokimov, Tinkoff Bank
MBLTDev15: Anna Mikhina, Maxim Evdokimov, Tinkoff Bank
e-Legion
 

More from e-Legion (20)

MBLT16: Elena Rydkina, Pure
MBLT16: Elena Rydkina, PureMBLT16: Elena Rydkina, Pure
MBLT16: Elena Rydkina, Pure
 
MBLT16: Alexander Lukin, AppMetrica
MBLT16: Alexander Lukin, AppMetricaMBLT16: Alexander Lukin, AppMetrica
MBLT16: Alexander Lukin, AppMetrica
 
MBLT16: Vincent Wu, Alibaba Mobile
MBLT16: Vincent Wu, Alibaba MobileMBLT16: Vincent Wu, Alibaba Mobile
MBLT16: Vincent Wu, Alibaba Mobile
 
MBLT16: Dmitriy Geranin, Afisha Restorany
MBLT16: Dmitriy Geranin, Afisha RestoranyMBLT16: Dmitriy Geranin, Afisha Restorany
MBLT16: Dmitriy Geranin, Afisha Restorany
 
MBLT16: Marvin Liao, 500Startups
MBLT16: Marvin Liao, 500StartupsMBLT16: Marvin Liao, 500Startups
MBLT16: Marvin Liao, 500Startups
 
MBLT16: Andrey Maslak, Aviasales
MBLT16: Andrey Maslak, AviasalesMBLT16: Andrey Maslak, Aviasales
MBLT16: Andrey Maslak, Aviasales
 
MBLT16: Andrey Bakalenko, Sberbank Online
MBLT16: Andrey Bakalenko, Sberbank OnlineMBLT16: Andrey Bakalenko, Sberbank Online
MBLT16: Andrey Bakalenko, Sberbank Online
 
Rx Java architecture
Rx Java architectureRx Java architecture
Rx Java architecture
 
Rx java
Rx javaRx java
Rx java
 
MBLTDev15: Hector Zarate, Spotify
MBLTDev15: Hector Zarate, SpotifyMBLTDev15: Hector Zarate, Spotify
MBLTDev15: Hector Zarate, Spotify
 
MBLTDev15: Cesar Valiente, Wunderlist
MBLTDev15: Cesar Valiente, WunderlistMBLTDev15: Cesar Valiente, Wunderlist
MBLTDev15: Cesar Valiente, Wunderlist
 
MBLTDev15: Brigit Lyons, Soundcloud
MBLTDev15: Brigit Lyons, SoundcloudMBLTDev15: Brigit Lyons, Soundcloud
MBLTDev15: Brigit Lyons, Soundcloud
 
MBLTDev15: Egor Tolstoy, Rambler&Co
MBLTDev15: Egor Tolstoy, Rambler&CoMBLTDev15: Egor Tolstoy, Rambler&Co
MBLTDev15: Egor Tolstoy, Rambler&Co
 
MBLTDev15: Alexander Orlov, Postforpost
MBLTDev15: Alexander Orlov, PostforpostMBLTDev15: Alexander Orlov, Postforpost
MBLTDev15: Alexander Orlov, Postforpost
 
MBLTDev15: Artemiy Sobolev, Parallels
MBLTDev15: Artemiy Sobolev, ParallelsMBLTDev15: Artemiy Sobolev, Parallels
MBLTDev15: Artemiy Sobolev, Parallels
 
MBLTDev15: Alexander Dimchenko, DIT
MBLTDev15: Alexander Dimchenko, DITMBLTDev15: Alexander Dimchenko, DIT
MBLTDev15: Alexander Dimchenko, DIT
 
MBLTDev: Evgeny Lisovsky, Litres
MBLTDev: Evgeny Lisovsky, LitresMBLTDev: Evgeny Lisovsky, Litres
MBLTDev: Evgeny Lisovsky, Litres
 
MBLTDev: Alexander Dimchenko, Bright Box
MBLTDev: Alexander Dimchenko, Bright Box MBLTDev: Alexander Dimchenko, Bright Box
MBLTDev: Alexander Dimchenko, Bright Box
 
MBLTDev15: Konstantin Goldshtein, Microsoft
MBLTDev15: Konstantin Goldshtein, MicrosoftMBLTDev15: Konstantin Goldshtein, Microsoft
MBLTDev15: Konstantin Goldshtein, Microsoft
 
MBLTDev15: Anna Mikhina, Maxim Evdokimov, Tinkoff Bank
MBLTDev15: Anna Mikhina, Maxim Evdokimov, Tinkoff Bank MBLTDev15: Anna Mikhina, Maxim Evdokimov, Tinkoff Bank
MBLTDev15: Anna Mikhina, Maxim Evdokimov, Tinkoff Bank
 

#MBLTdev: Опыт использования MVVM в реальных проектах

  • 1. MVVM в реальных проектах Юрий Буянов “Одноклассники”
  • 3. MVC
  • 4. “Massive View Controller” • Занимается вообще всем • Сильная связанность с View layer • Трудно тестировать • Трудно переиспользовать
  • 5. Model-View-ViewModel View (+ViewController) Lightweight View ViewModel Model UI logic Business logic
  • 6. Model-View-ViewModel View (+ViewController) Lightweight View ViewModel Model UI logic Business logic Bindings!
  • 7. ViewModel • Не знает ничего про ViewController • Не использует UIKit • Отображает (?) состояние UI с помощью KVO- совместимых свойств или RAC-сигналов • Действия представлены в виде методов или RAC- команд • Легко тестируема (и должна тестироваться)
  • 8. View (ViewController) • Декларативно привязывает состояние UI к состоянию VM • Обрабатывает чистую логику UI (вёрстка, анимации, ориентирование) • Может зависеть от нескольких ViewModel
  • 9. Биндинги - (void)viewDidLoad { [super viewDidLoad]; RAC(self.trackTitleLabel, text) = RACObserve(self.viewModel, trackTitle); RAC(self.playBtn, enabled) = RACObserve(self.viewModel, loading).not; } - (IBAction)nextBtnTap:(id)sender { [self.viewModel nextBtnPressed]; }
  • 10.
  • 11. View UI customization layout animations orientation changes ViewModel Model interaction (network, storage) Model-related UI state ??? Navigation Image Loading Action Confirmations UI-only actions …
  • 13.
  • 14. Ad hoc UINavigationController Sections Controller Talks Controller ctrl = [[TalksController alloc] init] 2 push 1 инициализация
  • 15. @implementation SectionsController - (IBAction)mobileBtnTap:(id)sender { UIViewController *ctrl = [[TalksController alloc] init]; [self.navigationController pushViewController:ctrl animated:YES]; } @end
  • 16. Ненужная связанность (coupling) @implementation SectionsController - (IBAction)mobileBtnTap:(id)sender { UIViewController *ctrl = [[TalksController alloc] init]; [self.navigationController pushViewController:ctrl animated:YES]; } @end
  • 17. Ad Hoc + MVVM UINavigationController Sections Controller Talks Controller 4 push 2 создаёт Sections ViewModel Talks ViewModel 1 действие создаёт 3
  • 18. @implementation SectionsViewModel - (void)mobileBtnPressed { MobileTalksViewModel *vm = [[MobileTalksViewModel alloc] init]; UIViewController *ctrl = [[TalksController alloc] initWithVM:vm]; [self.navigationController pushViewController:ctrl animated:YES]; } @end
  • 19. @implementation SectionsViewModel - (void)mobileBtnPressed { MobileTalksViewModel *vm = [[MobileTalksViewModel alloc] init]; UIViewController *ctrl = [[TalksController alloc] initWithVM:vm]; [self.navigationController pushViewController:ctrl animated:YES]; } @end Ненужная связанность UI-код внутри ViewModel! :(
  • 20. Решение “В лоб” UINavigationController Sections Controller Sections 2 создаёт ViewModel Talks ViewModel 1 действие
  • 21. Решение “В лоб” UINavigationController Sections Controller Sections 2 создаёт ViewModel Talks ViewModel 1 действие 3 сигнал
  • 22. Решение “В лоб” UINavigationController Sections Controller Talks Controller Sections 2 создаёт ViewModel Talks ViewModel 1 действие 3 сигнал 4 создаёт и связывает
  • 23. Решение “В лоб” UINavigationController Sections Controller Talks Controller 5 push Sections 2 создаёт ViewModel Talks ViewModel 1 действие 3 сигнал 4 создаёт и связывает
  • 24. @implementation SectionsViewModel - (void)mobileBtnPressed { MobileTalksViewModel *vm = [[MobileTalksViewModel alloc] init]; [_talksViewModelsSubject sendNext:vm]; } @end
  • 25. @implementation SectionsController - (IBAction)mobileBtnTap:(id)sender { [self.viewModel mobileBtnPressed]; } - (void)viewDidLoad { [self.viewModel.talksViewModelsSignal subscribeNext:^(id viewModel) { UIViewController* ctrl = [[TalksController alloc] initWithVM:viewModel]; [self.navigationController pushViewController:ctrl animated:YES]; }]; } @end
  • 26. Решение “В лоб” • Большая степень связанности в VM и контроллере • Негибкость • Повторение кода • Отдельный сигнал для каждого “маршрута”
  • 28. MVVM + Роутер UINavigationController Sections Controller 1 action 2 showTalks Sections ViewModel
  • 29. MVC + Роутер UINavigationController Sections Controller showDst
  • 30. Роутер • Имеет доступ к навигационным контроллерам (navigation controller, tab controller, drawer controller, menu controller) • Создаёт и конфигурирует экземпляры VM и контроллеров • (сам или используя DI-контейнер) • Осуществляет переходы между экранами • Mockable • Отлично работает в рамках MVVM и MVC
  • 31. Роутер @interface Router : NSObject - (void)showMobileTalks; - (void)showWebTalks; - (void)showGamesTalks; - (void)showTalk:(Talk*)talk; @end
  • 32. Роутер @implementation Router - (void)showMobileTalks { MobileTalksViewModel *vm = [[MobileTalksViewModel alloc] init]; UIViewController *ctrl = [[TalksController alloc] initWithVM:vm]; [self.mainNavigationController pushViewController:ctrl animated:YES]; } @end
  • 33. @implementation SectionsController - (IBAction)mobileBtnTap:(id)sender { [self.viewModel mobileBtnPressed]; } - (void)viewDidLoad { [self.viewModel.talksViewModelsSignal subscribeNext:^(id viewModel) { UIViewController* ctrl = [[TalksController alloc] initWithVM:viewModel]; [self.navigationController pushViewController:ctrl animated:YES]; }]; } @end
  • 34. @implementation SectionsViewModel - (void)mobileBtnPressed { [self.router showMobileTalks]; } @end
  • 35. Вложенные контроллеры UINavigationController Controller Child controller Some other controller ViewModel Child ViewModel Some other ViewModel
  • 36. Вложенные контроллеры UINavigationController Controller Child controller Some other controller ViewModel Child ViewModel Some other ViewModel
  • 38. Частный случай: URL-based роутер [self.router showMobileTalks]; [self.router open:@"/sections/mobile" modal:NO];
  • 39. URL-based роутер • Легко настраивается • Упрощает поддержку URL-схем • Упрощает переход от веб-приложений к нативным • Логика навигации может “утекать” в VM/контроллер • Сложности с передачей сложных объектов • Подходит не для всех приложений
  • 41. Модель ячейки ViewController ViewModel UICollectionView/UITableView Cell - (void)setViewModel:(MYCellViewModel *)viewModel CellViewModel CellViewModel CellViewModel CellViewModel - (void)viewDidLoad { [super viewDidLoad]; [self.viewModel.updatedContentSignal subscribeNext:^(id x) { [self.collectionView reloadData]; }]; } Cell Cell @property RACSubject *updatedContentSignal; NSArray *cellViewModels
  • 42. Статическая модель ячейки Cell - (void)setViewModel:(OKPTrackCellViewModel *)viewModel { NSParameterAssert(viewModel); self.titleLabel.text = viewModel.title; self.subTitleLabel.text = viewModel.subtitle; self.someIcon.hidden = !viewModel.someFlag; Cell ViewModel } @property NSString* title; @property NSString* subtitle; @property BOOL someFlag;
  • 43. Динамическая модель ячейки Cell - (void)setViewModel:(OKPTrackCellViewModel *)viewModel { NSParameterAssert(viewModel); self.titleLabel.text = viewModel.title; self.subTitleLabel.text = viewModel.subtitle; self.someIcon.hidden = !viewModel.someFlag; Cell ViewModel } @property NSString* title; @property NSString* subtitle; @property BOOL someFlag; //Может изменяться!
  • 44. Динамическая модель ячейки Cell RAC(self.someIcon, hidden) = RACObserve(viewModel.someFlag).not;
  • 45. Warning: cell reuse Cell RAC(self.someIcon, hidden) = RACObserve(viewModel.someFlag).not; /// A given key on an object should only have one active signal bound to it at any given time. Binding more than one signal to the same property is considered undefined behavior.
  • 46. Warning: cell reuse Cell RAC(self.someIcon, hidden) =[RACObserve(viewModel.someFlag).not takeUntil:self.rac_prepareForReuseSignal]; /// Solution: unsubscribe from RACObserve signal on cell reuse
  • 47. Ощущения (на данном этапе) • Технология “на вырост” • Сделает возможным написание тестов, но не напишет их за вас • Хинт: используйте Dependency Injection. • Вам придётся полюбить ReactiveCocoa