Сохранение состояния iOS-приложения, кое-что еще

Еще одна полезная возможность для разработчиков по сохранению состояния iOS-приложения (тема рассматривалась: часть 1, часть 2) – семантический идентификатор модели. Поясню суть на примере.

Допустим, в вашем приложении есть табличное представление (UITableView). По нажатию на одну из ячеек открылся контроллер, показывающий детальную информацию об элементе. И именно в таком состоянии приложение было закрыто.
С точки зрения удобства использования приложения – при возвращении из детального представления, таблица должна показывать те же записи, что и до перехода. Кроме того, подсветка выбора элемента таблицы должна пропасть с анимацией.
Оба этих действия делаются системой сохранения и восстановления состояния автоматически. Однако, по-умолчанию сохраняются только номера ячеек. Грубо говоря, сохраняется положение прокрутки “показывать ячейку в секции N, ряд M сверху“, а также “была выбрана ячейка в секции K, ряд L“.

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

Это можно реализовать, если в дополнение к протоколу UITableViewDataSource в вашем контроллере реализовать протокол UIDataSourceModelAssociation, это всего лишь два метода.

- (NSString *) modelIdentifierForElementAtIndexPath:(NSIndexPath *)idx inView:(UIView *)view;
- (NSIndexPath *) indexPathForElementWithModelIdentifier:(NSString *)identifier inView:(UIView *)view;

Первый из этих методов должен вернуть строку, однозначно идентифицирующую элемент данных таблицы по индексу idx. Второй – по строковому идентификатору должен вернуть индекс элемента.

Если вы используете Core Data (в данном примере используется NSFetchedResultsController), вы можете использовать свойство objectID (NSManagedObjectID).

- (NSString *) modelIdentifierForElementAtIndexPath:(NSIndexPath *)idx inView:(UIView *)view
{
    NSManagedObject *object = [self.fetchedResultsController objectAtIndexPath:idx];
    NSURL *objectIDURL = [object.objectID URIRepresentation];

    return [objectIDURL absoluteString];
}

- (NSIndexPath *) indexPathForElementWithModelIdentifier:(NSString *)identifier inView:(UIView *)view
{
    NSURL *objectIDURL = [NSURL URLWithString:identifier];
    NSManagedObjectID *objectID = [self.fetchedResultsController.managedObjectContext.persistentStoreCoordinator managedObjectIDForURIRepresentation:objectIDURL];
    NSManagedObject *object = [self.fetchedResultsController.managedObjectContext objectWithID:objectID];

    return [self.fetchedResultsController indexPathForObject:object];
}

Либо, если в используемой вами модели есть идентификаторы, которые можно привести к строковому представлению, можно использовать их.

Этот же подход должен применяться к представлениям коллекций (UICollectionView).

Как обычно, стоит почитать документацию Apple.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s