SlideShare a Scribd company logo
Андрей Резанов
Построение сложного
табличного интерфейса
7.8
Название
Тип
Тег №2Тег №1
Станция метро
Адерс места
Название места
Лучшие Недавние
Lorem ipsum dolor sit amet, consectetur
adipiscing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud
exercitation ullamco…... далее
Имя пользователя
Дата
Lorem ipsum dolor sit amet, consectetur
adipiscing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud
exercitation ullamco… далее
Заголовок блока
Важная информация
Дополнительная информация
Режим работы
Расписание работы
Режим работы:
7.8
Название
Тип
Станция метро
Адерс места
Название места
Лучшие Недавние
Заголовок блока
Важная информация
Lorem ipsum dolor sit amet, consectetur
adipiscing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud
exercitation ullamco… далее
Дополнительная информация
Дополнительная информация
Дополнительная информация
Тег №2Тег №1
Lorem ipsum dolor sit amet, consectetur
adipiscing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud
exercitation ullamco…... далее
Имя пользователя
Дата
Режим работы
Расписание работы
Режим работы:
7.8
Название
Тип
Лучшие Недавние
Заголовок блока
Важная информация
Lorem ipsum dolor sit amet, consectetur
adipiscing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud
exercitation ullamco…... далее
Имя пользователя
Дата
Режим работы
Расписание работы
Режим работы:
Lorem ipsum dolor sit amet, consectetur
adipiscing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud
exercitation ullamco… далее
Станция метро
Адерс места
Название места
Дополнительная информация
Дополнительная информация
Дополнительная информация
Дополнительная информация
Тег №2Тег №1
Построение сложного табличного интерфейса
Постановка задачи – Афиша iOS
• Уметь строить 30+ различных ячеек
• Располагать ячейки в различном порядке в зависимости
от 10 + конфигураций экрана
• В будущем необходимо добавлять новый ячейки /
конфигурации экрана
Построение сложного табличного интерфейса
Решение в лоб! Why not?
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
Creation *creation = [self itemAtIndexPath:indexPath];
NSString *cellIdentifier = [self cellIdentifierForObject:creation
atIndexPath:indexPath];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier
forIndexPath:indexPath];
if ([cellIdentifier isEqualToString:RCATitleTableViewCell]) {
TitleTableViewCell *titleCell = (TitleTableViewCell *)cell;
[titleCell fillWithCreation:creation];
} else if ([cellIdentifier isEqualToString:RCARatingTableViewCell]) {
RatingTableViewCell *ratingCell = (RatingTableViewCell *)cell;
[ratingCell fillWithRating:creation.rating];
}
...
return cell;
}
Построение сложного табличного интерфейса
• Неконтролируемый рост полотна кода в cellForRow
• Сложно добавлять новые ячейки, модифицировать
порядок ячеек
• Нарушение принципа единственной ответственности
(SOLID)
Решение в лоб - Проблемы
Построение сложного табличного интерфейса
Решение в лоб! Why not?
Декомпозиция
Построение сложного табличного интерфейса
Шаг 1. Внедряем View-модели 🐣
Модель представления - абстракция представления,
которая содержит свойства Модели.
Построение сложного табличного интерфейса
Шаг 1. Внедряем View-модели 🐣
Построение сложного табличного интерфейса
Класс TableViewModel
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
. . .
id viewModel = [self viewModelAtIndexPath:indexPath];
. . .
}
1. Получаем view-модель по indexPath
Построение сложного табличного интерфейса
Класс TableViewModel
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
. . .
Class cellClass = [self cellClassFromViewModel:viewModel];
. . .
}
2. Получаем класс ячейки у view-модели
Построение сложного табличного интерфейса
Класс TableViewModel
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
. . .
cell = [tableView
dequeueReusableCellWithIdentifier:NSStringFromClass(cellClass)];
. . .
}
3. Реюзаем / создаем ячейку
Построение сложного табличного интерфейса
Класс TableViewModel
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
. . .
[cell updateCellWithViewModel:viewModel];
. . .
}
4. Заполняем ячейку данными из view-модели
Построение сложного табличного интерфейса
Класс TableViewActions
- (CGFloat)tableView:(UITableView *)tableView
heightForRowAtIndexPath:(NSIndexPath *)indexPath {
. . .
id viewModel = [model viewModelAtIndexPath:indexPath];
. . .
}
1. Получаем view-модель по indexPath
Построение сложного табличного интерфейса
Класс TableViewActions
- (CGFloat)tableView:(UITableView *)tableView
heightForRowAtIndexPath:(NSIndexPath *)indexPath {
. . .
NSString *cellHeightID = [self cellHeightIDWithTableView:tableView
viewModel:viewModel];
NSNumber *cachedHeight = [self.cellHeightCache objectForKey:cellHeightID];
if (cachedHeight) {
return [cachedHeight floatValue];
}
. . .
}
2. Если есть закэшированное значение
высоты ячейки, то возвращаем его
Построение сложного табличного интерфейса
Класс TableViewActions
- (CGFloat)tableView:(UITableView *)tableView
heightForRowAtIndexPath:(NSIndexPath *)indexPath {
. . .
Class cellClass = [viewModel cellClass];
. . .
}
3. Получаем класс ячейки у view-модели
Построение сложного табличного интерфейса
Класс TableViewActions
- (CGFloat)tableView:(UITableView *)tableView
heightForRowAtIndexPath:(NSIndexPath *)indexPath {
. . .
CGFloat height;
if ([cellClass
respondsToSelector:@selector(heightForViewModel:atIndexPath:tableView:)]) {
height = [cellClass heightForViewModel:viewModel
atIndexPath:indexPath
tableView:tableView];
} else {
. . .
}
4. Если ячейки умеет сама рассчитывать
высоту, то возвращаем ее
Построение сложного табличного интерфейса
Класс TableViewActions
- (CGFloat)tableView:(UITableView *)tableView
heightForRowAtIndexPath:(NSIndexPath *)indexPath {
. . .
UITableViewCell<Cell> *cell = [self tableViewCellWithViewModel:tableView
tableView:tableView];
[cell updateCellWithViewModel:viewModel];
height = [self tableView:tableView heightForTableViewCell:cell];
. . .
}
5. Считаем высоту через статичный
прототип ячейки
Построение сложного табличного интерфейса
Класс TableViewActions
- (CGFloat)tableView:(UITableView *)tableView
heightForRowAtIndexPath:(NSIndexPath *)indexPath {
. . .
[cellHeightCache setObject:@(height)
forKey:cellHeightID];
. . .
}
6. Кэшируем значение высоты
Построение сложного табличного интерфейса
Чего-то не хватает?
Построение сложного табличного интерфейса
Метод построения view-моделей
2000 + строк кода
Построение сложного табличного интерфейса
Шаблон проектирования Строитель (англ. Builder)
Порождающий шаблон проектирования
предоставляет способ создания составного
объекта.
Построение сложного табличного интерфейса
Шаг 2. Внедряем Билдер
Построение сложного табличного интерфейса
Диаграмма последовательности (англ. Sequence diagram)
Построение сложного табличного интерфейса
Выводы
1. Внедрение view-моделей дает: слабую связность, дополнительный
слой между моделью и view
2. Никакой логики во view
3. Чистый и универсальный cellForRow, heightForRow
4. Внедрение билдера дает: разделение логики построения блоков ячеек
от логики сбора их вместе
5. Легкая возможность расширения данной схемы. Как появление новых
блоков/ячеек, так и появление новых экранов, например - для квестов!
6. Модульность кода
Построение сложного табличного интерфейса
Литература и ссылки
The "Gang of Four” - Design Patterns: Elements of Reusable
Object-Oriented Software
Erick Buck, Donald Yachtman - Cocoa Design Patterns
OBJC.IO Issue 13 - Architecture
OODesign.com - Builder pattern
NimbusKit - Table View Models
Построение сложного табличного интерфейса
Спасибо!

More Related Content

Viewers also liked

Rambler.iOS #1: Nimbus Kit Models
Rambler.iOS #1: Nimbus Kit ModelsRambler.iOS #1: Nimbus Kit Models
Rambler.iOS #1: Nimbus Kit Models
RAMBLER&Co
 
RDSDataSource: Чистые тесты на Swift
RDSDataSource: Чистые тесты на SwiftRDSDataSource: Чистые тесты на Swift
RDSDataSource: Чистые тесты на Swift
RAMBLER&Co
 
RDSDataSource: Promises
RDSDataSource: PromisesRDSDataSource: Promises
RDSDataSource: Promises
RAMBLER&Co
 
Usability. Пользовательский интерфейс и представление информации
Usability. Пользовательский интерфейс и представление информацииUsability. Пользовательский интерфейс и представление информации
Usability. Пользовательский интерфейс и представление информации
Silver Digital
 
принципы проектирования интерфейса (37)
принципы проектирования интерфейса (37)принципы проектирования интерфейса (37)
принципы проектирования интерфейса (37)
romachka_pole
 
Павел Манахов, Поиск причин юзабилити-проблем
Павел Манахов, Поиск причин юзабилити-проблемПавел Манахов, Поиск причин юзабилити-проблем
Павел Манахов, Поиск причин юзабилити-проблем
Mail.ru Group
 
Rambler.iOS #7: Прием платежей по банковским картам в iOS приложении
Rambler.iOS #7: Прием платежей по банковским картам в iOS приложенииRambler.iOS #7: Прием платежей по банковским картам в iOS приложении
Rambler.iOS #7: Прием платежей по банковским картам в iOS приложении
RAMBLER&Co
 
RDSDataSource: Мастер-класс по Dip
RDSDataSource: Мастер-класс по DipRDSDataSource: Мастер-класс по Dip
RDSDataSource: Мастер-класс по Dip
RAMBLER&Co
 
Rambler.iOS #8: Как не стать жертвой бэкендеров
Rambler.iOS #8: Как не стать жертвой бэкендеровRambler.iOS #8: Как не стать жертвой бэкендеров
Rambler.iOS #8: Как не стать жертвой бэкендеров
RAMBLER&Co
 
RDSDataSource: OCLint
RDSDataSource: OCLintRDSDataSource: OCLint
RDSDataSource: OCLint
RAMBLER&Co
 
Rambler.iOS #7: Интернет-эквайринг 101
Rambler.iOS #7: Интернет-эквайринг 101Rambler.iOS #7: Интернет-эквайринг 101
Rambler.iOS #7: Интернет-эквайринг 101
RAMBLER&Co
 
RDSDataSource: Автогенерация документации для SDK
RDSDataSource: Автогенерация документации для SDKRDSDataSource: Автогенерация документации для SDK
RDSDataSource: Автогенерация документации для SDK
RAMBLER&Co
 
Rambler.iOS #5: Разбираем Massive View Controller
Rambler.iOS #5: Разбираем Massive View ControllerRambler.iOS #5: Разбираем Massive View Controller
Rambler.iOS #5: Разбираем Massive View Controller
RAMBLER&Co
 
Rambler.iOS #6: Не рычите на pbxproj
Rambler.iOS #6: Не рычите на pbxprojRambler.iOS #6: Не рычите на pbxproj
Rambler.iOS #6: Не рычите на pbxproj
RAMBLER&Co
 
RDSDataSource: YapDatabase
RDSDataSource: YapDatabaseRDSDataSource: YapDatabase
RDSDataSource: YapDatabase
RAMBLER&Co
 
Rambler.iOS #5: Подмодули в VIPER
Rambler.iOS #5: Подмодули в VIPERRambler.iOS #5: Подмодули в VIPER
Rambler.iOS #5: Подмодули в VIPER
RAMBLER&Co
 
RDSDataSource: App Thinning
RDSDataSource: App ThinningRDSDataSource: App Thinning
RDSDataSource: App Thinning
RAMBLER&Co
 
Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы
Rambler.iOS #4: Создание модульных приложений на примере Рамблер.КассыRambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы
Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы
RAMBLER&Co
 
RDSDataSource: iOS Reverse Engineering for inexperienced
RDSDataSource: iOS Reverse Engineering for inexperiencedRDSDataSource: iOS Reverse Engineering for inexperienced
RDSDataSource: iOS Reverse Engineering for inexperienced
RAMBLER&Co
 
Rambler.iOS #5: VIPER и Swift
Rambler.iOS #5: VIPER и SwiftRambler.iOS #5: VIPER и Swift
Rambler.iOS #5: VIPER и Swift
RAMBLER&Co
 

Viewers also liked (20)

Rambler.iOS #1: Nimbus Kit Models
Rambler.iOS #1: Nimbus Kit ModelsRambler.iOS #1: Nimbus Kit Models
Rambler.iOS #1: Nimbus Kit Models
 
RDSDataSource: Чистые тесты на Swift
RDSDataSource: Чистые тесты на SwiftRDSDataSource: Чистые тесты на Swift
RDSDataSource: Чистые тесты на Swift
 
RDSDataSource: Promises
RDSDataSource: PromisesRDSDataSource: Promises
RDSDataSource: Promises
 
Usability. Пользовательский интерфейс и представление информации
Usability. Пользовательский интерфейс и представление информацииUsability. Пользовательский интерфейс и представление информации
Usability. Пользовательский интерфейс и представление информации
 
принципы проектирования интерфейса (37)
принципы проектирования интерфейса (37)принципы проектирования интерфейса (37)
принципы проектирования интерфейса (37)
 
Павел Манахов, Поиск причин юзабилити-проблем
Павел Манахов, Поиск причин юзабилити-проблемПавел Манахов, Поиск причин юзабилити-проблем
Павел Манахов, Поиск причин юзабилити-проблем
 
Rambler.iOS #7: Прием платежей по банковским картам в iOS приложении
Rambler.iOS #7: Прием платежей по банковским картам в iOS приложенииRambler.iOS #7: Прием платежей по банковским картам в iOS приложении
Rambler.iOS #7: Прием платежей по банковским картам в iOS приложении
 
RDSDataSource: Мастер-класс по Dip
RDSDataSource: Мастер-класс по DipRDSDataSource: Мастер-класс по Dip
RDSDataSource: Мастер-класс по Dip
 
Rambler.iOS #8: Как не стать жертвой бэкендеров
Rambler.iOS #8: Как не стать жертвой бэкендеровRambler.iOS #8: Как не стать жертвой бэкендеров
Rambler.iOS #8: Как не стать жертвой бэкендеров
 
RDSDataSource: OCLint
RDSDataSource: OCLintRDSDataSource: OCLint
RDSDataSource: OCLint
 
Rambler.iOS #7: Интернет-эквайринг 101
Rambler.iOS #7: Интернет-эквайринг 101Rambler.iOS #7: Интернет-эквайринг 101
Rambler.iOS #7: Интернет-эквайринг 101
 
RDSDataSource: Автогенерация документации для SDK
RDSDataSource: Автогенерация документации для SDKRDSDataSource: Автогенерация документации для SDK
RDSDataSource: Автогенерация документации для SDK
 
Rambler.iOS #5: Разбираем Massive View Controller
Rambler.iOS #5: Разбираем Massive View ControllerRambler.iOS #5: Разбираем Massive View Controller
Rambler.iOS #5: Разбираем Massive View Controller
 
Rambler.iOS #6: Не рычите на pbxproj
Rambler.iOS #6: Не рычите на pbxprojRambler.iOS #6: Не рычите на pbxproj
Rambler.iOS #6: Не рычите на pbxproj
 
RDSDataSource: YapDatabase
RDSDataSource: YapDatabaseRDSDataSource: YapDatabase
RDSDataSource: YapDatabase
 
Rambler.iOS #5: Подмодули в VIPER
Rambler.iOS #5: Подмодули в VIPERRambler.iOS #5: Подмодули в VIPER
Rambler.iOS #5: Подмодули в VIPER
 
RDSDataSource: App Thinning
RDSDataSource: App ThinningRDSDataSource: App Thinning
RDSDataSource: App Thinning
 
Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы
Rambler.iOS #4: Создание модульных приложений на примере Рамблер.КассыRambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы
Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы
 
RDSDataSource: iOS Reverse Engineering for inexperienced
RDSDataSource: iOS Reverse Engineering for inexperiencedRDSDataSource: iOS Reverse Engineering for inexperienced
RDSDataSource: iOS Reverse Engineering for inexperienced
 
Rambler.iOS #5: VIPER и Swift
Rambler.iOS #5: VIPER и SwiftRambler.iOS #5: VIPER и Swift
Rambler.iOS #5: VIPER и Swift
 

Similar to Rambler.iOS #7: Построение сложного табличного интерфейса

"Адаптивный дизайн интерфейса JS API Яндекс.Карт и особенности его реализации...
"Адаптивный дизайн интерфейса JS API Яндекс.Карт и особенности его реализации..."Адаптивный дизайн интерфейса JS API Яндекс.Карт и особенности его реализации...
"Адаптивный дизайн интерфейса JS API Яндекс.Карт и особенности его реализации...
Yandex
 
Работа с БД в Java
Работа с БД в JavaРабота с БД в Java
Работа с БД в Java
metaform
 
Swift + Kotlin = ❤, Станислав Таланов и Сергей Моляк. 8 июня, 2019
Swift + Kotlin = ❤, Станислав Таланов и Сергей Моляк. 8 июня, 2019Swift + Kotlin = ❤, Станислав Таланов и Сергей Моляк. 8 июня, 2019
Swift + Kotlin = ❤, Станислав Таланов и Сергей Моляк. 8 июня, 2019
Mail.ru Group
 
Хранение данных в iPhone. (FMDB, SQL-Persistence, CoreData)
Хранение данных в iPhone. (FMDB, SQL-Persistence, CoreData)Хранение данных в iPhone. (FMDB, SQL-Persistence, CoreData)
Хранение данных в iPhone. (FMDB, SQL-Persistence, CoreData)Yandex
 
My batis
My batisMy batis
Встреча №8. NSIncrementalStore, или как заставить Core Data варить ваш собств...
Встреча №8. NSIncrementalStore, или как заставить Core Data варить ваш собств...Встреча №8. NSIncrementalStore, или как заставить Core Data варить ваш собств...
Встреча №8. NSIncrementalStore, или как заставить Core Data варить ваш собств...
CocoaHeads
 
ES2015+: давно пора!
ES2015+: давно пора!ES2015+: давно пора!
ES2015+: давно пора!
Vitebsk Miniq
 
Take more from Jquery
Take more from JqueryTake more from Jquery
Take more from JqueryMagento Dev
 
iOS-05_2-UIKit
iOS-05_2-UIKitiOS-05_2-UIKit
iOS-05_2-UIKit
Noveo
 
Being SOLID
Being SOLIDBeing SOLID
Being SOLID
Sergey Krapivenskiy
 
ASP.NET MVC - как построить по-настоящему гибкое веб-приложение
ASP.NET MVC - как построить по-настоящему гибкое веб-приложениеASP.NET MVC - как построить по-настоящему гибкое веб-приложение
ASP.NET MVC - как построить по-настоящему гибкое веб-приложение
Alexander Byndyu
 
MyBatis на практике
MyBatis на практикеMyBatis на практике
MyBatis на практике
Vitebsk Miniq
 
Objective-C 2.0: краткое описание языка и рантайма
Objective-C 2.0: краткое описание языка и рантаймаObjective-C 2.0: краткое описание языка и рантайма
Objective-C 2.0: краткое описание языка и рантаймаYandex
 
Курсы по мобильной разработке. 1 лекция. Знакомство с iOS
Курсы по мобильной разработке. 1 лекция. Знакомство с iOSКурсы по мобильной разработке. 1 лекция. Знакомство с iOS
Курсы по мобильной разработке. 1 лекция. Знакомство с iOSГлеб Тарасов
 
Встреча №9. Алгоритмы и коллекции стандартных библиотек C++, C#, Java, Object...
Встреча №9. Алгоритмы и коллекции стандартных библиотек C++, C#, Java, Object...Встреча №9. Алгоритмы и коллекции стандартных библиотек C++, C#, Java, Object...
Встреча №9. Алгоритмы и коллекции стандартных библиотек C++, C#, Java, Object...
CocoaHeads
 
ASP.NET MVC за пределами Hello World. Дятлов Александр D2D Just.NET
ASP.NET MVC за пределами Hello World. Дятлов Александр D2D Just.NETASP.NET MVC за пределами Hello World. Дятлов Александр D2D Just.NET
ASP.NET MVC за пределами Hello World. Дятлов Александр D2D Just.NET
Dev2Dev
 
SCINO. Android для начинающих. Занятие 10
SCINO. Android для начинающих. Занятие 10SCINO. Android для начинающих. Занятие 10
SCINO. Android для начинающих. Занятие 10
SCINO
 
[JAM 1.1] Clean Code (Paul Malikov)
[JAM 1.1] Clean Code (Paul Malikov)[JAM 1.1] Clean Code (Paul Malikov)
[JAM 1.1] Clean Code (Paul Malikov)
Evgeny Kaziak
 
TК°Conf. 10 проблем автоматизации UI и их решение с помощью JDI. Роман Иовлев.
TК°Conf. 10 проблем автоматизации UI и их решение с помощью JDI. Роман Иовлев.TК°Conf. 10 проблем автоматизации UI и их решение с помощью JDI. Роман Иовлев.
TК°Conf. 10 проблем автоматизации UI и их решение с помощью JDI. Роман Иовлев.
TKConf
 

Similar to Rambler.iOS #7: Построение сложного табличного интерфейса (20)

"Адаптивный дизайн интерфейса JS API Яндекс.Карт и особенности его реализации...
"Адаптивный дизайн интерфейса JS API Яндекс.Карт и особенности его реализации..."Адаптивный дизайн интерфейса JS API Яндекс.Карт и особенности его реализации...
"Адаптивный дизайн интерфейса JS API Яндекс.Карт и особенности его реализации...
 
Работа с БД в Java
Работа с БД в JavaРабота с БД в Java
Работа с БД в Java
 
msumobi2. Лекция 2
msumobi2. Лекция 2msumobi2. Лекция 2
msumobi2. Лекция 2
 
Swift + Kotlin = ❤, Станислав Таланов и Сергей Моляк. 8 июня, 2019
Swift + Kotlin = ❤, Станислав Таланов и Сергей Моляк. 8 июня, 2019Swift + Kotlin = ❤, Станислав Таланов и Сергей Моляк. 8 июня, 2019
Swift + Kotlin = ❤, Станислав Таланов и Сергей Моляк. 8 июня, 2019
 
Хранение данных в iPhone. (FMDB, SQL-Persistence, CoreData)
Хранение данных в iPhone. (FMDB, SQL-Persistence, CoreData)Хранение данных в iPhone. (FMDB, SQL-Persistence, CoreData)
Хранение данных в iPhone. (FMDB, SQL-Persistence, CoreData)
 
My batis
My batisMy batis
My batis
 
Встреча №8. NSIncrementalStore, или как заставить Core Data варить ваш собств...
Встреча №8. NSIncrementalStore, или как заставить Core Data варить ваш собств...Встреча №8. NSIncrementalStore, или как заставить Core Data варить ваш собств...
Встреча №8. NSIncrementalStore, или как заставить Core Data варить ваш собств...
 
ES2015+: давно пора!
ES2015+: давно пора!ES2015+: давно пора!
ES2015+: давно пора!
 
Take more from Jquery
Take more from JqueryTake more from Jquery
Take more from Jquery
 
iOS-05_2-UIKit
iOS-05_2-UIKitiOS-05_2-UIKit
iOS-05_2-UIKit
 
Being SOLID
Being SOLIDBeing SOLID
Being SOLID
 
ASP.NET MVC - как построить по-настоящему гибкое веб-приложение
ASP.NET MVC - как построить по-настоящему гибкое веб-приложениеASP.NET MVC - как построить по-настоящему гибкое веб-приложение
ASP.NET MVC - как построить по-настоящему гибкое веб-приложение
 
MyBatis на практике
MyBatis на практикеMyBatis на практике
MyBatis на практике
 
Objective-C 2.0: краткое описание языка и рантайма
Objective-C 2.0: краткое описание языка и рантаймаObjective-C 2.0: краткое описание языка и рантайма
Objective-C 2.0: краткое описание языка и рантайма
 
Курсы по мобильной разработке. 1 лекция. Знакомство с iOS
Курсы по мобильной разработке. 1 лекция. Знакомство с iOSКурсы по мобильной разработке. 1 лекция. Знакомство с iOS
Курсы по мобильной разработке. 1 лекция. Знакомство с iOS
 
Встреча №9. Алгоритмы и коллекции стандартных библиотек C++, C#, Java, Object...
Встреча №9. Алгоритмы и коллекции стандартных библиотек C++, C#, Java, Object...Встреча №9. Алгоритмы и коллекции стандартных библиотек C++, C#, Java, Object...
Встреча №9. Алгоритмы и коллекции стандартных библиотек C++, C#, Java, Object...
 
ASP.NET MVC за пределами Hello World. Дятлов Александр D2D Just.NET
ASP.NET MVC за пределами Hello World. Дятлов Александр D2D Just.NETASP.NET MVC за пределами Hello World. Дятлов Александр D2D Just.NET
ASP.NET MVC за пределами Hello World. Дятлов Александр D2D Just.NET
 
SCINO. Android для начинающих. Занятие 10
SCINO. Android для начинающих. Занятие 10SCINO. Android для начинающих. Занятие 10
SCINO. Android для начинающих. Занятие 10
 
[JAM 1.1] Clean Code (Paul Malikov)
[JAM 1.1] Clean Code (Paul Malikov)[JAM 1.1] Clean Code (Paul Malikov)
[JAM 1.1] Clean Code (Paul Malikov)
 
TК°Conf. 10 проблем автоматизации UI и их решение с помощью JDI. Роман Иовлев.
TК°Conf. 10 проблем автоматизации UI и их решение с помощью JDI. Роман Иовлев.TК°Conf. 10 проблем автоматизации UI и их решение с помощью JDI. Роман Иовлев.
TК°Conf. 10 проблем автоматизации UI и их решение с помощью JDI. Роман Иовлев.
 

More from RAMBLER&Co

RDSDataSource: Основы LLVM
RDSDataSource: Основы LLVMRDSDataSource: Основы LLVM
RDSDataSource: Основы LLVM
RAMBLER&Co
 
Rambler.iOS #9: Анализируй это!
Rambler.iOS #9: Анализируй это!Rambler.iOS #9: Анализируй это!
Rambler.iOS #9: Анализируй это!
RAMBLER&Co
 
Rambler.iOS #9: Нужны ли бэкенд-разработчики, когда есть Swift?
Rambler.iOS #9: Нужны ли бэкенд-разработчики, когда есть Swift?Rambler.iOS #9: Нужны ли бэкенд-разработчики, когда есть Swift?
Rambler.iOS #9: Нужны ли бэкенд-разработчики, когда есть Swift?
RAMBLER&Co
 
Rambler.iOS #9: Life with out of memory
Rambler.iOS #9: Life with out of memoryRambler.iOS #9: Life with out of memory
Rambler.iOS #9: Life with out of memory
RAMBLER&Co
 
RDSDataSource: Построение UML диаграмм
RDSDataSource: Построение UML диаграммRDSDataSource: Построение UML диаграмм
RDSDataSource: Построение UML диаграмм
RAMBLER&Co
 
Rambler.iOS #8: Чистые unit-тесты
Rambler.iOS #8: Чистые unit-тестыRambler.iOS #8: Чистые unit-тесты
Rambler.iOS #8: Чистые unit-тесты
RAMBLER&Co
 
Rambler.iOS #8: Сервис-ориентированная архитектура
Rambler.iOS #8: Сервис-ориентированная архитектураRambler.iOS #8: Сервис-ориентированная архитектура
Rambler.iOS #8: Сервис-ориентированная архитектура
RAMBLER&Co
 
Rambler.iOS #8: Make your app extensible with JavaScriptCore
Rambler.iOS #8: Make your app extensible with JavaScriptCoreRambler.iOS #8: Make your app extensible with JavaScriptCore
Rambler.iOS #8: Make your app extensible with JavaScriptCore
RAMBLER&Co
 
RDSDataSource: Плюрализация в iOS
RDSDataSource: Плюрализация в iOSRDSDataSource: Плюрализация в iOS
RDSDataSource: Плюрализация в iOS
RAMBLER&Co
 
RDSDataSource: Flux, Redux, ReSwift
RDSDataSource: Flux, Redux, ReSwiftRDSDataSource: Flux, Redux, ReSwift
RDSDataSource: Flux, Redux, ReSwift
RAMBLER&Co
 
Rambler.iOS #6: App delegate - разделяй и властвуй
Rambler.iOS #6: App delegate - разделяй и властвуйRambler.iOS #6: App delegate - разделяй и властвуй
Rambler.iOS #6: App delegate - разделяй и властвуй
RAMBLER&Co
 
Rambler.iOS #6: Pagination Demystified
Rambler.iOS #6: Pagination DemystifiedRambler.iOS #6: Pagination Demystified
Rambler.iOS #6: Pagination Demystified
RAMBLER&Co
 
Rambler.iOS #5: TDD и VIPER
Rambler.iOS #5: TDD и VIPERRambler.iOS #5: TDD и VIPER
Rambler.iOS #5: TDD и VIPER
RAMBLER&Co
 
Rambler.iOS #5: Переходы и передача данных между VIPER модулями
Rambler.iOS #5: Переходы и передача данных между VIPER модулямиRambler.iOS #5: Переходы и передача данных между VIPER модулями
Rambler.iOS #5: Переходы и передача данных между VIPER модулями
RAMBLER&Co
 
Rambler.iOS #5: VIPER a la Rambler
Rambler.iOS #5: VIPER a la RamblerRambler.iOS #5: VIPER a la Rambler
Rambler.iOS #5: VIPER a la Rambler
RAMBLER&Co
 

More from RAMBLER&Co (15)

RDSDataSource: Основы LLVM
RDSDataSource: Основы LLVMRDSDataSource: Основы LLVM
RDSDataSource: Основы LLVM
 
Rambler.iOS #9: Анализируй это!
Rambler.iOS #9: Анализируй это!Rambler.iOS #9: Анализируй это!
Rambler.iOS #9: Анализируй это!
 
Rambler.iOS #9: Нужны ли бэкенд-разработчики, когда есть Swift?
Rambler.iOS #9: Нужны ли бэкенд-разработчики, когда есть Swift?Rambler.iOS #9: Нужны ли бэкенд-разработчики, когда есть Swift?
Rambler.iOS #9: Нужны ли бэкенд-разработчики, когда есть Swift?
 
Rambler.iOS #9: Life with out of memory
Rambler.iOS #9: Life with out of memoryRambler.iOS #9: Life with out of memory
Rambler.iOS #9: Life with out of memory
 
RDSDataSource: Построение UML диаграмм
RDSDataSource: Построение UML диаграммRDSDataSource: Построение UML диаграмм
RDSDataSource: Построение UML диаграмм
 
Rambler.iOS #8: Чистые unit-тесты
Rambler.iOS #8: Чистые unit-тестыRambler.iOS #8: Чистые unit-тесты
Rambler.iOS #8: Чистые unit-тесты
 
Rambler.iOS #8: Сервис-ориентированная архитектура
Rambler.iOS #8: Сервис-ориентированная архитектураRambler.iOS #8: Сервис-ориентированная архитектура
Rambler.iOS #8: Сервис-ориентированная архитектура
 
Rambler.iOS #8: Make your app extensible with JavaScriptCore
Rambler.iOS #8: Make your app extensible with JavaScriptCoreRambler.iOS #8: Make your app extensible with JavaScriptCore
Rambler.iOS #8: Make your app extensible with JavaScriptCore
 
RDSDataSource: Плюрализация в iOS
RDSDataSource: Плюрализация в iOSRDSDataSource: Плюрализация в iOS
RDSDataSource: Плюрализация в iOS
 
RDSDataSource: Flux, Redux, ReSwift
RDSDataSource: Flux, Redux, ReSwiftRDSDataSource: Flux, Redux, ReSwift
RDSDataSource: Flux, Redux, ReSwift
 
Rambler.iOS #6: App delegate - разделяй и властвуй
Rambler.iOS #6: App delegate - разделяй и властвуйRambler.iOS #6: App delegate - разделяй и властвуй
Rambler.iOS #6: App delegate - разделяй и властвуй
 
Rambler.iOS #6: Pagination Demystified
Rambler.iOS #6: Pagination DemystifiedRambler.iOS #6: Pagination Demystified
Rambler.iOS #6: Pagination Demystified
 
Rambler.iOS #5: TDD и VIPER
Rambler.iOS #5: TDD и VIPERRambler.iOS #5: TDD и VIPER
Rambler.iOS #5: TDD и VIPER
 
Rambler.iOS #5: Переходы и передача данных между VIPER модулями
Rambler.iOS #5: Переходы и передача данных между VIPER модулямиRambler.iOS #5: Переходы и передача данных между VIPER модулями
Rambler.iOS #5: Переходы и передача данных между VIPER модулями
 
Rambler.iOS #5: VIPER a la Rambler
Rambler.iOS #5: VIPER a la RamblerRambler.iOS #5: VIPER a la Rambler
Rambler.iOS #5: VIPER a la Rambler
 

Rambler.iOS #7: Построение сложного табличного интерфейса

  • 2. 7.8 Название Тип Тег №2Тег №1 Станция метро Адерс места Название места Лучшие Недавние Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco…... далее Имя пользователя Дата Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco… далее Заголовок блока Важная информация Дополнительная информация Режим работы Расписание работы Режим работы:
  • 3. 7.8 Название Тип Станция метро Адерс места Название места Лучшие Недавние Заголовок блока Важная информация Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco… далее Дополнительная информация Дополнительная информация Дополнительная информация Тег №2Тег №1 Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco…... далее Имя пользователя Дата Режим работы Расписание работы Режим работы:
  • 4. 7.8 Название Тип Лучшие Недавние Заголовок блока Важная информация Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco…... далее Имя пользователя Дата Режим работы Расписание работы Режим работы: Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco… далее Станция метро Адерс места Название места Дополнительная информация Дополнительная информация Дополнительная информация Дополнительная информация Тег №2Тег №1
  • 5. Построение сложного табличного интерфейса Постановка задачи – Афиша iOS • Уметь строить 30+ различных ячеек • Располагать ячейки в различном порядке в зависимости от 10 + конфигураций экрана • В будущем необходимо добавлять новый ячейки / конфигурации экрана
  • 6. Построение сложного табличного интерфейса Решение в лоб! Why not? - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { Creation *creation = [self itemAtIndexPath:indexPath]; NSString *cellIdentifier = [self cellIdentifierForObject:creation atIndexPath:indexPath]; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath]; if ([cellIdentifier isEqualToString:RCATitleTableViewCell]) { TitleTableViewCell *titleCell = (TitleTableViewCell *)cell; [titleCell fillWithCreation:creation]; } else if ([cellIdentifier isEqualToString:RCARatingTableViewCell]) { RatingTableViewCell *ratingCell = (RatingTableViewCell *)cell; [ratingCell fillWithRating:creation.rating]; } ... return cell; }
  • 7. Построение сложного табличного интерфейса • Неконтролируемый рост полотна кода в cellForRow • Сложно добавлять новые ячейки, модифицировать порядок ячеек • Нарушение принципа единственной ответственности (SOLID) Решение в лоб - Проблемы
  • 8. Построение сложного табличного интерфейса Решение в лоб! Why not? Декомпозиция
  • 9. Построение сложного табличного интерфейса Шаг 1. Внедряем View-модели 🐣 Модель представления - абстракция представления, которая содержит свойства Модели.
  • 10. Построение сложного табличного интерфейса Шаг 1. Внедряем View-модели 🐣
  • 11. Построение сложного табличного интерфейса Класс TableViewModel - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { . . . id viewModel = [self viewModelAtIndexPath:indexPath]; . . . } 1. Получаем view-модель по indexPath
  • 12. Построение сложного табличного интерфейса Класс TableViewModel - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { . . . Class cellClass = [self cellClassFromViewModel:viewModel]; . . . } 2. Получаем класс ячейки у view-модели
  • 13. Построение сложного табличного интерфейса Класс TableViewModel - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { . . . cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass(cellClass)]; . . . } 3. Реюзаем / создаем ячейку
  • 14. Построение сложного табличного интерфейса Класс TableViewModel - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { . . . [cell updateCellWithViewModel:viewModel]; . . . } 4. Заполняем ячейку данными из view-модели
  • 15. Построение сложного табличного интерфейса Класс TableViewActions - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { . . . id viewModel = [model viewModelAtIndexPath:indexPath]; . . . } 1. Получаем view-модель по indexPath
  • 16. Построение сложного табличного интерфейса Класс TableViewActions - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { . . . NSString *cellHeightID = [self cellHeightIDWithTableView:tableView viewModel:viewModel]; NSNumber *cachedHeight = [self.cellHeightCache objectForKey:cellHeightID]; if (cachedHeight) { return [cachedHeight floatValue]; } . . . } 2. Если есть закэшированное значение высоты ячейки, то возвращаем его
  • 17. Построение сложного табличного интерфейса Класс TableViewActions - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { . . . Class cellClass = [viewModel cellClass]; . . . } 3. Получаем класс ячейки у view-модели
  • 18. Построение сложного табличного интерфейса Класс TableViewActions - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { . . . CGFloat height; if ([cellClass respondsToSelector:@selector(heightForViewModel:atIndexPath:tableView:)]) { height = [cellClass heightForViewModel:viewModel atIndexPath:indexPath tableView:tableView]; } else { . . . } 4. Если ячейки умеет сама рассчитывать высоту, то возвращаем ее
  • 19. Построение сложного табличного интерфейса Класс TableViewActions - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { . . . UITableViewCell<Cell> *cell = [self tableViewCellWithViewModel:tableView tableView:tableView]; [cell updateCellWithViewModel:viewModel]; height = [self tableView:tableView heightForTableViewCell:cell]; . . . } 5. Считаем высоту через статичный прототип ячейки
  • 20. Построение сложного табличного интерфейса Класс TableViewActions - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { . . . [cellHeightCache setObject:@(height) forKey:cellHeightID]; . . . } 6. Кэшируем значение высоты
  • 21. Построение сложного табличного интерфейса Чего-то не хватает?
  • 22. Построение сложного табличного интерфейса Метод построения view-моделей 2000 + строк кода
  • 23. Построение сложного табличного интерфейса Шаблон проектирования Строитель (англ. Builder) Порождающий шаблон проектирования предоставляет способ создания составного объекта.
  • 24. Построение сложного табличного интерфейса Шаг 2. Внедряем Билдер
  • 25. Построение сложного табличного интерфейса Диаграмма последовательности (англ. Sequence diagram)
  • 26. Построение сложного табличного интерфейса Выводы 1. Внедрение view-моделей дает: слабую связность, дополнительный слой между моделью и view 2. Никакой логики во view 3. Чистый и универсальный cellForRow, heightForRow 4. Внедрение билдера дает: разделение логики построения блоков ячеек от логики сбора их вместе 5. Легкая возможность расширения данной схемы. Как появление новых блоков/ячеек, так и появление новых экранов, например - для квестов! 6. Модульность кода
  • 27. Построение сложного табличного интерфейса Литература и ссылки The "Gang of Four” - Design Patterns: Elements of Reusable Object-Oriented Software Erick Buck, Donald Yachtman - Cocoa Design Patterns OBJC.IO Issue 13 - Architecture OODesign.com - Builder pattern NimbusKit - Table View Models
  • 28. Построение сложного табличного интерфейса Спасибо!