Построение сложного табличного интерфейса

28
Андрей Резанов Построение сложного табличного интерфейса

Upload: rambler-ios

Post on 21-Feb-2017

435 views

Category:

Technology


1 download

TRANSCRIPT

Андрей Резанов

Построение сложного табличного интерфейса

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. Никакой логики во view3. Чистый и универсальный cellForRow, heightForRow4. Внедрение билдера дает: разделение логики построения блоков ячеек от логики сбора их вместе

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

Построение сложного табличного интерфейса

Спасибо!