Обсуждение

Обсуждение

В коде вашего пользовательского интерфейса вам может понадобиться удалять ячейки и/или разделы. Например, у вас может иметься переключатель (типа UISwitch, см. раздел 1.2). Когда пользователь нажимает переключатель, вам, возможно, требуется добавить в табличный вид несколько строк. После того как пользователь вернет переключатель в исходное положение, вам, вероятно, потребуется вновь убрать эти строки с экрана. Но такие операции удаления не всегда ограничиваются ячейками (строками) табличного вида. Иногда из табличного вида требуется одновременно удалить целый раздел (или несколько разделов). Ключевой аспект при удалении разделов и ячеек из табличных видов состоит в том, что сначала из источника данных удаляется информация, соответствующая этим элементам (ячейкам или разделам), а потом вызываются соответствующие методы удаления, применяемые к табличному виду. После того как метод удаления завершит работу, табличный вид снова будет ссылаться на свой объект из источника данных. Если же после операции удаления количество ячеек/разделов в источнике данных не совпадет с количеством ячеек/разделов в табличном виде, приложение аварийно завершится. Но не волнуйтесь — даже если вы и допустите такую ошибку, то отладочное сообщение, которое появится на консоли, будет достаточно подробным для того, чтобы вы могли подправить код.

Рассмотрим, как удалять разделы из табличного вида. В данном разделе мы отобразим табличный вид в контроллере вида, который, в свою очередь, будет находиться в навигационном контроллере. Внутри табличного вида будет два раздела: один для нечетных чисел, другой — для четных. В табличном виде в разделе с нечетными числами мы отобразим только 1, 3, 5 и 7, а в разделе с четными — 0, 2, 4 и 6. В первом упражнении мы собираемся создать на навигационной панели специальную кнопку, которая будет удалять раздел с нечетными числами. На рис. 4.15 показано, какой результат мы хотим получить.

Рис. 4.15. Пользовательский интерфейс для отображения двух разделов табличного вида; в интерфейсе есть кнопка, удаляющая раздел Odd Numbers (Нечетные числа)

Начнем с главного. Определим контроллер вида:

#import <UIKit/UIKit.h>

static NSString *CellIdentifier = @"NumbersCellIdentifier";

@interface ViewController: UIViewController <UITableViewDelegate,

UITableViewDataSource>

@property (nonatomic, strong) UITableView *tableViewNumbers;

@property (nonatomic, strong) NSMutableDictionary *dictionaryOfNumbers;

@property (nonatomic, strong) UIBarButtonItem *barButtonAction;

@end

Свойство tableViewNumbers соответствует нашему табличному виду. Свойство barButtonAction соответствует кнопке для удаления, которая будет отображаться на навигационной панели. И последнее, но немаловажное свойство dictionaryOfNumbers — это источник данных для табличного вида. В данном словаре мы поместим два значения типа NSMutableArray, которые будут содержать числа типа NSNumber. Это изменяемые массивы, позже в данной главе мы сможем удалять их отдельно от массивов, содержащихся в словаре. Ключи для этих массивов мы будем хранить как статические значения в файле реализации контроллера вида. По этой причине позже просто сможем извлечь массивы из словаря, пользуясь статическими ключами. (Если бы ключи не были статическими, то для нахождения массивов в словаре пришлось бы выполнять сравнение строк. А эта операция требует больше времени, чем обычное ассоциирование объекта со статическим ключом, не изменяющимся на протяжении всего существования контроллера вида.) Теперь синтезируем наши свойства и определим статические строковые ключи для массивов, находящихся в словаре источника данных:

static NSString *SectionOddNumbers = @"Odd Numbers";

static NSString *SectionEvenNumbers = @"Even Numbers";

@implementation ViewController

Теперь, перед тем как создать табличный вид, необходимо заполнить информацией словарь источника данных. Вот простой метод, который автоматически заполнит словарь:

— (NSMutableDictionary *) dictionaryOfNumbers{

if (_dictionaryOfNumbers == nil){

NSMutableArray *arrayOfEvenNumbers =

[[NSMutableArray alloc] initWithArray:@[

@0,

@2,

@4,

@6,

]];

NSMutableArray *arrayOfOddNumbers =

[[NSMutableArray alloc] initWithArray:@[

@1,

@3,

@5,

@7,

]];

_dictionaryOfNumbers =

[[NSMutableDictionary alloc]

initWithDictionary:@{

SectionEvenNumbers: arrayOfEvenNumbers,

SectionOddNumbers: arrayOfOddNumbers,

}];

}

return _dictionaryOfNumbers;

}

Пока все нормально? Как видите, у нас два массива, в каждом из которых содержатся некоторые числа (в одном нечетные, в другом — четные). Мы ассоциируем массивы с ключами SectionEvenNumbers и SectionOddNumbers, которые ранее определили в файле реализации контроллера вида. Теперь инстанцируем табличный вид:

— (void)viewDidLoad

{

[super viewDidLoad];

self.barButtonAction =

[[UIBarButtonItem alloc]

initWithTitle:@"Delete Odd Numbers"

style: UIBarButtonItemStylePlain

target: self

action:@selector(deleteOddNumbersSection:)];

[self.navigationItem setRightBarButtonItem: self.barButtonAction

animated: NO];

self.tableViewNumbers = [[UITableView alloc]

initWithFrame: self.view.frame

style: UITableViewStyleGrouped];

self.tableViewNumbers.autoresizingMask = UIViewAutoresizingFlexibleWidth |

UIViewAutoresizingFlexibleHeight;

self.tableViewNumbers.delegate = self;

self.tableViewNumbers.dataSource = self;

[self.view addSubview: self.tableViewNumbers];

}

Далее нужно заполнить табличный вид информацией внутри словаря источника с данными:

— (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView{

return self.dictionaryOfNumbers.allKeys.count;

}

— (NSInteger) tableView:(UITableView *)tableView

numberOfRowsInSection:(NSInteger)section{

NSString *sectionNameInDictionary =

self.dictionaryOfNumbers.allKeys[section];

NSArray *sectionArray = self.dictionaryOfNumbers[sectionNameInDictionary];

return sectionArray.count;

}

— (UITableViewCell *) tableView:(UITableView *)tableView

cellForRowAtIndexPath:(NSIndexPath *)indexPath{

UITableViewCell *cell = nil;

cell = [tableView dequeueReusableCellWithIdentifier: CellIdentifier

forIndexPath: indexPath];

NSString *sectionNameInDictionary =

self.dictionaryOfNumbers.allKeys[indexPath.section];

NSArray *sectionArray = self.dictionaryOfNumbers[sectionNameInDictionary];

NSNumber *number = sectionArray[indexPath.row];

cell.textLabel.text = [NSString stringWithFormat:@"%lu",

(unsigned long)[number unsignedIntegerValue]];

return cell;

}

— (NSString *) tableView:(UITableView *)tableView

titleForHeaderInSection:(NSInteger)section{

return self.dictionaryOfNumbers.allKeys[section];

}

Навигационная кнопка связана с селектором deleteOddNumbersSection:. Этот метод нам сейчас предстоит запрограммировать. Цель метода, как видно из его названия[2], — найти раздел, соответствующий всем нечетным числам в источнике данных, найти табличный вид, а потом удалить искомый раздел и из таблицы, и из источника данных. Вот как это делается:

— (void) deleteOddNumbersSection:(id)paramSender{

/* Сначала удаляем раздел из источника данных. */

NSString *key = SectionOddNumbers;

NSInteger indexForKey = [[self.dictionaryOfNumbers allKeys]

indexOfObject: key];

if (indexForKey == NSNotFound){

NSLog(@"Could not find the section in the data source.");

return;

}

[self.dictionaryOfNumbers removeObjectForKey: key];

/* Затем удаляем раздел из табличного вида. */

NSIndexSet *sectionToDelete = [NSIndexSet indexSetWithIndex: indexForKey];

[self.tableViewNumbers deleteSections: sectionToDelete

withRowAnimation: UITableViewRowAnimationAutomatic];

/* Наконец, убираем с навигационной панели кнопку,

так как она нам больше не понадобится. */

[self.navigationItem setRightBarButtonItem: nil animated: YES];

}

Все довольно просто. Теперь, когда пользователь нажмет кнопку на навигационной панели, раздел Odd Numbers (Нечетные числа) исчезнет из табличного вида. Как видите, в процессе удаления раздела табличный вид анимируется. Это происходит потому, что мы передали анимационный тип UITableViewRowAnimationAutomatic параметру withRowAnimation: метода deleteSections: withRowAnimation: табличного вида. Теперь запустите приложение в эмуляторе iOS и выполните Debug — Toggle Slow Animations (Отладка — Включить медленную анимацию). Потом попробуйте нажать кнопку на навигационной панели и посмотрите, что происходит. Как видите, удаление сопровождается медленной анимацией (движением). Красиво, правда? Когда удаление завершится, приложение будет выглядеть, как на рис. 4.16.

Рис. 4.16. Раздел, содержащий нечетные числа, удален из табличного вида

Вы уже знаете, как удалять разделы из табличных видов. Перейдем к удалению ячеек. Мы собираемся изменить функциональность навигационной кнопки так, чтобы при ее нажатии во всех разделах табличного вида удалялись все ячейки, содержащие числовое значение больше 2. Таким образом, мы удалим все четные и нечетные числа больше 2. Итак, изменим навигационную кнопку в методе viewDidLoad контроллера вида:

— (void)viewDidLoad {

[super viewDidLoad];

self.barButtonAction =

[[UIBarButtonItem alloc]

initWithTitle:@"Delete Numbers > 2"

style: UIBarButtonItemStylePlain

target: self

action:@selector(deleteNumbersGreaterThan2:)];

[self.navigationItem setRightBarButtonItem: self.barButtonAction

animated: NO];

self.tableViewNumbers = [[UITableView alloc]

initWithFrame: self.view.frame

style: UITableViewStyleGrouped];

self.tableViewNumbers.autoresizingMask =

UIViewAutoresizingFlexibleWidth |

UIViewAutoresizingFlexibleHeight;

self.tableViewNumbers.delegate = self;

self.tableViewNumbers.dataSource = self;

[self.view addSubview: self.tableViewNumbers];

}

На рис. 4.17 показано, как выглядит приложение при запуске в эмуляторе iPhone.

Рис. 4.17. Кнопка, удаляющая все ячейки с числами больше 2

Теперь кнопка навигационной панели связана с селектором deleteNumbersGreaterThan2:. Селектор — это метод, реализованный в контроллере вида. Но прежде, чем перейти к его программированию, определим, что этот метод должен сделать.

1. Найти оба массива с нечетными и четными числами в источнике данных и собрать индексные пути (типа NSIndexPath) чисел больше 2. Позже мы будем пользоваться этими индексными путями для удаления соответствующих ячеек в табличном виде.

2. Удалить все числа больше 2 из источника данных — как из словаря для нечетных чисел, так и из словаря для четных.

3. Удалить из табличного вида соответствующие ячейки. Индексные пути к этим ячейкам мы собрали на первом этапе.

4. Удалить кнопку с навигационной панели. Эта кнопка больше не понадобится, ведь ячейки уже удалены и из источника данных, и из табличного вида. В качестве альтернативы при желании можете просто отключить эту кнопку. Но мне кажется, что для удобства пользователя кнопку лучше просто удалить, поскольку отключенная кнопка все равно будет ему совершенно бесполезна.

— (void) deleteNumbersGreaterThan2:(id)paramSender{

NSMutableArray *arrayOfIndexPathsToDelete =

[[NSMutableArray alloc] init];

NSMutableArray *arrayOfNumberObjectsToDelete =

[[NSMutableArray alloc] init];

/* Шаг 1: собираем объекты, которые мы хотим удалить из

источника данных, а также их индексные пути. */

__block NSUInteger keyIndex = 0;

[self.dictionaryOfNumbers enumerateKeysAndObjectsUsingBlock:

^(NSString *key, NSMutableArray *object, BOOL *stop) {

[object enumerateObjectsUsingBlock:

^(NSNumber *number, NSUInteger numberIndex, BOOL *stop) {

if ([number unsignedIntegerValue] > 2){

NSIndexPath *indexPath =

[NSIndexPath indexPathForRow: numberIndex

inSection: keyIndex];

[arrayOfIndexPathsToDelete addObject: indexPath];

[arrayOfNumberObjectsToDelete addObject: number];

}

}];

keyIndex++;

}];

/* Шаг 2: удаляем объекты из источника данных. */

if ([arrayOfNumberObjectsToDelete count] > 0){

NSMutableArray *arrayOfOddNumbers =

self.dictionaryOfNumbers[SectionOddNumbers];

NSMutableArray *arrayOfEvenNumbers =

self.dictionaryOfNumbers[SectionEvenNumbers];

[arrayOfNumberObjectsToDelete enumerateObjectsUsingBlock:

^(NSNumber *numberToDelete, NSUInteger idx, BOOL *stop) {

if ([arrayOfOddNumbers indexOfObject: numberToDelete]

!= NSNotFound){

[arrayOfOddNumbers removeObject: numberToDelete];

}

if ([arrayOfEvenNumbers indexOfObject: numberToDelete]

!= NSNotFound){

[arrayOfEvenNumbers removeObject: numberToDelete];

}

}];

}

/* Шаг 3: удаляем все ячейки, соответствующие объектам. */

[self.tableViewNumbers

deleteRowsAtIndexPaths: arrayOfIndexPathsToDelete

withRowAnimation: UITableViewRowAnimationAutomatic];

[self.navigationItem setRightBarButtonItem: nil animated: YES];

}

После того как пользователь нажмет кнопку на навигационной панели, все ячейки, в которых содержатся числа больше 2, будут удалены из источника данных. Табличный вид и все приложение станут выглядеть как на рис. 4.18.

Рис. 4.18. Мы удалили все ячейки, в которых содержались числа больше 2

Данный текст является ознакомительным фрагментом.



Поделитесь на страничке

Следующая глава >

Похожие главы из других книг:

Обсуждение

Из книги автора

Обсуждение Обычно после того, как пользователь успешно снимет фотографию на устройство с iOS, он ожидает, что этот снимок сохранится в его библиотеке фотографий. Однако приложения, не входящие в стандартный комплект программ iOS, могут запросить пользователя сделать снимок


Обсуждение

Из книги автора

Обсуждение Фреймворк Assets Library — удобный посредник между разработчиком и библиотекой фотографий. Как будет указано в разделе 13.6, в iOS SDK вам предоставляются встроенные компоненты графического пользовательского интерфейса, которыми можно пользоваться для доступа к


Обсуждение

Из книги автора

Обсуждение Чтобы пользователь мог выбирать фотоснимки или видеоролики из своей библиотеки фотографий, необходимо установить свойство sourceType экземпляра UIImagePickerController в значение UIImagePickerControllerSourceTypePhotoLibrary и только потом открывать перед пользователем инструмент для выбора


Обсуждение

Из книги автора

Обсуждение Библиотека ресурсов подразделяется на группы. В каждой группе содержатся ресурсы, а каждый ресурс имеет свойства, например URL (универсальные локаторы ресурсов) и объекты представления.Все ресурсы всех типов можно получать из библиотеки ресурсов с помощью


Обсуждение

Из книги автора

Обсуждение Класс UIVideoEditorController, содержащийся в iOS SDK, позволяет программисту вывести на экран перед пользователем специальный интерфейс для редактирования. Все, что требуется сделать, — предоставить URL видеоролика, который предполагается отредактировать, а потом


Обсуждение

Из книги автора

Обсуждение В зависимости от того, на работу в какой версии iOS рассчитано ваше приложение, его можно запускать и выполнять на различных устройствах, где установлены разные версии iOS. Например, вы можете разрабатывать приложение в последней версии iOS SDK, но в качестве целевой


Обсуждение

Из книги автора

Обсуждение Когда приложение переходит в фоновый режим, работа его основного потока приостанавливается. Потоки, которые вы создаете в своем приложении с помощью метода класса detachNewThreadSelector: toTarget: withObject:, относящегося к классу NSThread, также приостанавливаются. Если вы


Обсуждение

Из книги автора

Обсуждение Многие приложения, ежедневно поступающие на рынок App Store, обладают возможностями соединения с теми или иными серверами. Некоторые выбирают с сервера данные для обновления, другие отсылают информацию на сервер и т. д. В течение долгого времени в iOS существовал


Обсуждение

Из книги автора

Обсуждение В iOS приложение может запросить продолжить воспроизведение своих аудиофайлов, даже если оно само переходит в фоновый режим. В этом разделе мы воспользуемся плеером AVAudioPlayer, который прост и удобен в обращении. Наша задача — запустить аудиоплеер и воспроизвести


Обсуждение

Из книги автора

Обсуждение Когда приложение работает в приоритетном режиме, можно получать от экземпляра CLLocationManager делегатные сообщения, информирующие вас о том, что iOS обнаружила перемещение устройства на новое место. Однако если приложение переходит в фоновый режим и становится


Обсуждение

Из книги автора

Обсуждение Допустим, пустое приложение iOS (то есть приложение всего с одним окном, для которого еще не написан код) впервые запускается на устройстве с iOS, поддерживающем работу в многозадачном режиме. Оно запускается именно впервые, а не возвращается из фонового режима в


Обсуждение

Из книги автора

Обсуждение При работе с приложениями, которые используют класс NSURLConnection, но, уходя в фоновый режим, не запрашивают у iOS дополнительного времени, обращаться с соединениями не составляет никакого труда. Рассмотрим на примере, как будет действовать асинхронное соединение,


Обсуждение

Из книги автора

Обсуждение Пока ваше приложение работает в фоновом режиме, может произойти многое! Например, пользователь может вдруг изменить локализацию устройства с iOS на странице Settings (Настройки) и задать, к примеру, испанский язык вместо английского. Приложения могут


Обсуждение

Из книги автора

Обсуждение В приложениях, написанных для iOS, файл пакета настроек может быть предоставлен пользователю для внесения собственных настроек. Эти настройки будут доступны пользователю в приложении (Settings) на устройстве. Чтобы лучше понять, как работает этот механизм,


Обсуждение

Из книги автора

Обсуждение Пуш-уведомления похожи на локальные уведомления тем, что позволяют сообщать пользователю определенную информацию, даже если ваше приложение неактивно при поступлении уведомления. В то время как локальные уведомления назначаются самим приложением,