Алексей Патосин «Как можно доработать UITableViewController, чтобы облегчить себе жизнь»

3,611 views

Published on

Алексей Патосин «Как можно доработать UITableViewController, чтобы облегчить себе жизнь»

Yandex Mobile Camp в Санкт-Петербурге 2012
http://events.yandex.ru/events/yamobcamp/spb-may-2012/

Я затрону проблемы, с которыми сталкивался каждый, работая с таблицами в Cocoa Touch. Я расскажу, как можно улучшить существующий подход, как элегантно избавиться от «копипасты» и сфокусироваться только на том, какие данные и в какой структуре показывать. Разработанный подход позволяет свести написание кода при создании таких таблиц и форм к минимуму.

0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
3,611
On SlideShare
0
From Embeds
0
Number of Embeds
3,208
Actions
Shares
0
Downloads
9
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

Алексей Патосин «Как можно доработать UITableViewController, чтобы облегчить себе жизнь»

  1. 1. Yandex Mobile Camp Санкт-ПетербургКак можно доработать UITableViewController чтобы облегчить себе жизнь Патосин Алексей YotaLab
  2. 2. Agenda1. Проблемы работы с таблицами под iOS2. У нас есть решение3. We need to go deeper 1
  3. 3. Давайте поговорим о Cocoa таблицах
  4. 4. Таблицы вокруг нас 3
  5. 5. Какие бывают таблицы?1. Списки однородных элементов 2. Формы (1-... сущностей) (всё не так страшно) (сейчас немного поковыряем) 4
  6. 6. Сложные формы Ночной кошмар, если таблица динамическаяПоказывать всегда Показывать всегдаТелефон +7(800)123-666-7 Телефон +7(800)123-666-7Email steve@apple.com Email steve@apple.comДобавить поле Добавить полеСейчас онлайн Сейчас онлайн Ringo Star Ringo Star Jimmy Page 5 мин5 мин 10 мин10 мин 15 мин15 мин ПолчасаПолчаса Если выбрано 15 минут и больше, то тут появляется этот текст 5
  7. 7. Типичные способы управления сложной таблицей – Гроздь switch/case – State machine – Разруливание вариантов гроздями наследников 6
  8. 8. Минусы использования UITableViewController (обо что спотыкался каждый)– Настройка таблиц через UITableViewControllerDelegate (хочется задать все параметры в конструкторе/билдере)– Заполнение и обновление таблицы через UITableViewControllerDataSource (мы ненавидим indexPath)– Работа с ячейкой (ячейка “не знает”, что на неё нажали) 7
  9. 9. Чего хочется?
  10. 10. Чего хочется?– Абстрагироваться от работы с таблицей и работать сданными– Хочется, чтобы таблица стала более “smart” - таблица знала когда себя обновлять - ячейки знали когда себя обновлять - модель знала, что происходит в ячейках– Хочется реинвентить дата биндинг под iOS 9
  11. 11. “smart” ячейка таблицыХочется, чтобы ячейка стала самостоятельнымэлементом и знала: 10
  12. 12. “smart” ячейка таблицыХочется, чтобы ячейка стала самостоятельнымэлементом и знала: model view +7 800 123 6667 что показывать (model > view) 10
  13. 13. “smart” ячейка таблицыХочется, чтобы ячейка стала самостоятельнымэлементом и знала: model view +7 800 123 что обновлять (view changed > model changed) model view +7 800 123 6667 10
  14. 14. “smart” ячейка таблицыХочется, чтобы ячейка стала самостоятельнымэлементом и знала: view model +7 800 123 4567 когда обновлять (model changed > view changed) model view model view +7 800 123 6667 +7 800 123 10
  15. 15. Houston, we have a solution
  16. 16. Структура таблицыLorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean consectetuer.AbraCadabraCarambaLorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean consectetuer. 12
  17. 17. Структура таблицы sectionLorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean consectetuer.AbraCadabraCarambaLorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean consectetuer. 12
  18. 18. Структура таблицы sectionLorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean consectetuer.Abra CadabraCarambaLorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean consectetuer. 12
  19. 19. Структура таблицы sectionLorem ipsum dolor sit amet, consectetuer cells adipiscing elit. Aenean consectetuer.Abra CadabraCarambaLorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean consectetuer. 12
  20. 20. Структура таблицы sectionLorem ipsum dolor sit amet, consectetuer cells adipiscing elit. Aenean consectetuer.Abra headerTitle Cadabra headerViewCaramba headerHeightLorem ipsum dolor sit amet, consectetuer footerTitle adipiscing elit. Aenean consectetuer. footerView footerHeight 12
  21. 21. Структура таблицы sectionLorem ipsum dolor sit amet, consectetuer cells adipiscing elit. Aenean consectetuer.Abra headerTitle Cadabra headerViewCaramba headerHeightLorem ipsum dolor sit amet, consectetuer footerTitle adipiscing elit. Aenean consectetuer. footerView footerHeight 12
  22. 22. Структура таблицы sectionLorem ipsum dolor sit amet, consectetuer cells cellActions adipiscing elit. Aenean consectetuer.Abra headerTitle Cadabra headerViewCaramba headerHeightLorem ipsum dolor sit amet, consectetuer footerTitle adipiscing elit. Aenean consectetuer. footerView footerHeight 12
  23. 23. Мы выделили следующие типы ячеек 13
  24. 24. Мы выделили следующие типы ячеек– Push Добавить поле– State - Switch Показывать всегда - Check 10 мин– Edit Email steve@apple.com - Flexible edit Телефон +7(800)123-666-7– Text Сейчас онлайн 12/32 13
  25. 25. SmartTableViewController UITableViewController UITableViewControllerDelegate UITableViewControllerDataSourceSmartTableViewController UITableViewCell TableSectionContainer AbstractSmartTableViewCell PushTableViewCell TextTableViewCell EditTableViewCell AbstractStateTableViewCell FlexibleEditTableViewCell SwitchTableViewCell CheckTableViewCell 14
  26. 26. Какая главная особенность “smart” ячейки?При создании ячейки действие задаётся через блок     [cell setCalledBlock:^{         NSLog(@"Hello there..");     }];Действия: - нажатие на ячейке - нажатие на переключателе - ввод текста в ячейке accessoryType появляется автоматически, если задан calledBlock 15
  27. 27. Какие вкусности есть у “smart” таблицы? Оптимизированная работа с нотификациями NSNotification с использованием блока    [self addNotificationObserver:@"NotificationName"  object:_jet  usingBlock:^(NSNotification *notification){         //do smth     } calledBlockImmediately:YES]; (сейчас увидим как это работает) 16
  28. 28. Какие вкусности есть у “smart” таблицы?Нотификации очищаются самостоятельно, если не нужнадругая логика - (void) removeNotificationObservers{   [_notifications enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {       [[NSNotificationCenter defaultCenter] removeObserver:obj];   }];   [_notifications removeAllObjects]; } - (void) dealloc{      [self removeNotificationObservers];   [_notifications release];        [super dealloc]; } нотификации храняться в словаре, следовательно один инстанс viewController не может хранить несколько нотификаций с одинаковыми именами 17
  29. 29. Как заполнять структуру таблицы- (void)updateSections{    [super updateSections];        [sections addObject:[self pilotSection]];    [sections addObject:[self jetSection]];    [sections addObject:[self weaponSection]];         [self.tableView reloadData];} 18
  30. 30. Как заполнять структуру таблицы- (void)updateSections{    [super updateSections];         [sections addObject:[self pilotSection]];    [sections addObject:[self jetSection]];    [sections addObject:[self weaponSection]];         [self.tableView reloadData];} 18
  31. 31. Как заполнять структуру таблицы- (void)updateSections{    [super updateSections];         [sections addObject:[self pilotSection]];    [sections addObject:[self jetSection]];    [sections addObject:[self weaponSection]];         [self.tableView reloadData];} 18
  32. 32. Как заполнять структуру таблицы- (void)updateSections{    [super updateSections];         [sections addObject:[self pilotSection]];    [sections addObject:[self jetSection]];    [sections addObject:[self weaponSection]];         [self.tableView reloadData];} 18
  33. 33. Как создавать секции- (TableSectionContainer *)pilotSection{    TableSectionContainer *section = [TableSectionContainer sectionWithSectionId:pilotSectionId];        section.headerTitle = @"Pilot";            [section.cells addObject:[self pilotCell]];        [section setFooterTitle:@"pilot name and range are required"];    [section setFooterHeight:20];              return section;} 19
  34. 34. Как создавать секции- (TableSectionContainer *)pilotSection{    TableSectionContainer *section = [TableSectionContainer sectionWithSectionId:pilotSectionId];        section.headerTitle = @"Pilot";            [section.cells addObject:[self pilotCell]];        [section setFooterTitle:@"pilot name and range are required"];    [section setFooterHeight:20];              return section;} 19
  35. 35. Как создавать секции- (TableSectionContainer *)pilotSection{    TableSectionContainer *section = [TableSectionContainer sectionWithSectionId:pilotSectionId];        section.headerTitle = @"Pilot";            [section.cells addObject:[self pilotCell]];        [section setFooterTitle:@"pilot name and range are required"];    [section setFooterHeight:20];              return section;} 19
  36. 36. Как создавать секции- (TableSectionContainer *)pilotSection{    TableSectionContainer *section = [TableSectionContainer sectionWithSectionId:pilotSectionId];        section.headerTitle = @"Pilot";            [section.cells addObject:[self pilotCell]];        [section setFooterTitle:@"pilot name and range are required"];    [section setFooterHeight:20];              return section;} 19
  37. 37. Как создавать секции- (TableSectionContainer *)pilotSection{    TableSectionContainer *section = [TableSectionContainer sectionWithSectionId:pilotSectionId];        section.headerTitle = @"Pilot";            [section.cells addObject:[self pilotCell]];        [section setFooterTitle:@"pilot name and range are required"];    [section setFooterHeight:20];              return section;} 19
  38. 38. Как создавать ячейки- (PushTableViewCell *)pilotCell{    PushTableViewCell *cell = [PushTableViewCell cellWithCellId:pilotCellId];        __block typeof(self) bself = self;        [cell setCalledBlock:^{        [bself showPilotViewController];    }];        [self addNotificationObserver:@"PilotNameChanged" object:_jet.pilot  usingBlock: ^(NSNotification *notification){  cell.textLabel.text = [NSString  stringWithFormat:@"%@ %@", bself.jet.pilot.pilotName, [bself.jet.pilot pilotRangeDescription]];      } calledBlockImmediately:YES];        return cell;} 20
  39. 39. Как создавать ячейки- (PushTableViewCell *)pilotCell{    PushTableViewCell *cell = [PushTableViewCell cellWithCellId:pilotCellId];        __block typeof(self) bself = self;        [cell setCalledBlock:^{        [bself showPilotViewController];    }];        [self addNotificationObserver:@"PilotNameChanged" object:_jet.pilot  usingBlock: ^(NSNotification *notification){  cell.textLabel.text = [NSString  stringWithFormat:@"%@ %@", bself.jet.pilot.pilotName, [bself.jet.pilot pilotRangeDescription]];      } calledBlockImmediately:YES];        return cell;} 20
  40. 40. Как создавать ячейки- (PushTableViewCell *)pilotCell{    PushTableViewCell *cell = [PushTableViewCell cellWithCellId:pilotCellId];        __block typeof(self) bself = self;        [cell setCalledBlock:^{        [bself showPilotViewController];    }];        [self addNotificationObserver:@"PilotNameChanged" object:_jet.pilot  usingBlock: ^(NSNotification *notification){  cell.textLabel.text = [NSString  stringWithFormat:@"%@ %@", bself.jet.pilot.pilotName, [bself.jet.pilot pilotRangeDescription]];      } calledBlockImmediately:YES];        return cell;} 20
  41. 41. Как создавать ячейки- (PushTableViewCell *)pilotCell{    PushTableViewCell *cell = [PushTableViewCell cellWithCellId:pilotCellId];        __block typeof(self) bself = self;        [cell setCalledBlock:^{        [bself showPilotViewController];    }];        [self addNotificationObserver:@"PilotNameChanged" object:_jet.pilot  usingBlock: ^(NSNotification *notification){  cell.textLabel.text = [NSString  stringWithFormat:@"%@ %@", bself.jet.pilot.pilotName, [bself.jet.pilot pilotRangeDescription]];      } calledBlockImmediately:YES];        return cell;} 20
  42. 42. Как создавать ячейки- (PushTableViewCell *)pilotCell{    PushTableViewCell *cell = [PushTableViewCell cellWithCellId:pilotCellId];        __block typeof(self) bself = self;        [cell setCalledBlock:^{        [bself showPilotViewController];    }];        [self addNotificationObserver:@"PilotNameChanged" object:_jet.pilot  usingBlock: ^(NSNotification *notification){  cell.textLabel.text = [NSString  stringWithFormat:@"%@ %@", bself.jet.pilot.pilotName, [bself.jet.pilot pilotRangeDescription]];      } calledBlockImmediately:YES];        return cell;} 20
  43. 43. Как создавать ячейки- (PushTableViewCell *)pilotCell{    PushTableViewCell *cell = [PushTableViewCell cellWithCellId:pilotCellId];        __block typeof(self) bself = self;        [cell setCalledBlock:^{        [bself showPilotViewController];    }];        [self addNotificationObserver:@"PilotNameChanged" object:_jet.pilot  usingBlock: ^(NSNotification *notification){  cell.textLabel.text = [NSString  stringWithFormat:@"%@ %@", bself.jet.pilot.pilotName, [bself.jet.pilot pilotRangeDescription]];      } calledBlockImmediately:YES];        return cell;} 20
  44. 44. Как создавать ячейки- (PushTableViewCell *)pilotCell{    PushTableViewCell *cell = [PushTableViewCell cellWithCellId:pilotCellId];        __block typeof(self) bself = self;        [cell setCalledBlock:^{        [bself showPilotViewController];    }];        [self addNotificationObserver:@"PilotNameChanged" object:_jet.pilot  usingBlock: ^(NSNotification *notification){  cell.textLabel.text = [NSString  stringWithFormat:@"%@ %@", bself.jet.pilot.pilotName, [bself.jet.pilot pilotRangeDescription]];      } calledBlockImmediately:YES];        return cell;} 20
  45. 45. Некоторые нюансы специфичных ячеекStateTableViewCell и её потомки Check и Switch [cell setCalledBlock:^{      bself.jet.isOn = ! bself.jet.isOn;  }]; 21
  46. 46. Некоторые нюансы специфичных ячеекEditTableViewCell     [cell setCalledBlock:^{         bself.jet.pilotName = cell.valueTextField.text;          }]; 22
  47. 47. Некоторые нюансы специфичных ячеекFlexibleEditTableViewCell typedef void(^CalledBlock)(void); typedef BOOL(^ShouldChangeCharactersInRange)(NSRange range, NSString *string); typedef BOOL(^TextFieldShouldReturnBlock)(void); typedef BOOL(^TextFieldShouldClearBlock)(void); ShouldChangeCharactersInRange _shouldChangeCharactersInRangeBlock; TextFieldShouldReturnBlock _textFieldShouldReturnBlock; TextFieldShouldClearBlock _textFieldShouldClearBlock; CalledBlock _textFieldDidBeginEditingBlock; CalledBlock _textFieldDidEndEditingBlock; 23
  48. 48. Что есть ещё?Ячейка помимо блоков может использовать классическуюконструкцию delegate, selector, object1, object2 cell.delegate = self; cell.selector = @selector(doSmth:); cell.object1ToAction = obj; 24
  49. 49. Что есть ещё?Ячейка может на событие вызывать viewController имякоторого задано при её создании cell.viewControllerNameForPush = @”PilotViewController”; 25
  50. 50. Что есть ещё?Таблица содержит гибкий механизм обновления секций и ячеек insertSection:atIndex: insertCell:inSection:atIndex: insertCells:inSection:atIndex: removeSection: removeCell:inSection: replaceSection:withSection: replaceCell:inSection:withCell: replaceSectionWithArrayOfSections: (для обращения к нужной секции или ячейки используется её уникальный идентификатор, задаваемый при создании) 26
  51. 51. Thank you!alexey.patosin.rualexey@patosin.ru@gn0meavpSmartTableViewController:http://bit.ly/N8hcMe

×