Управление жизненным циклом документа
Документ проходит через типичный жизненный цикл. Основанное на документе приложение ответственно за управление его прогрессом через тот цикл. Как Вы видите из следующего списка, большинство этих событий жизненного цикла инициируется пользователем:
Пользователь сначала создает документ.
Пользователь открывает существующий документ и отображения приложения это в представлении или представлениях документа.
Пользователь редактирует документ.
Пользователь может попросить помещать документ в хранение iCloud или может запросить удаление документа от хранения iCloud.
Во время редактирования могут произойти сохранение, или другие действия, ошибки или конфликты; приложение должно узнать об этих ошибках и конфликтах и или попытаться обработать их или сообщить пользователю.
Пользователь закрывает выбранный документ.
Пользователь удаляет существующий документ.
Следующие разделы обсуждают процедуры, которые основанное на документе приложение должно завершить для этих операций жизненного цикла.
Установка предпочтительного места хранения для файлов документов
Все документы приложения хранятся или в локальной тестовой среде или в каталоге контейнера iCloud. Пользователь не должен быть в состоянии выбрать отдельные документы для хранения в iCloud.
Когда приложение запускается впервые на устройстве, оно должно сделать следующее:
Если iCloud не сконфигурирован, скажите пользователям, что они должны сконфигурировать iCloud, если они хотят сохранить файлы там.
Если iCloud сконфигурирован, но не включен для приложения, спросите пользователей, если они хотят включить iCloud — другими словами, спросить, хотят ли они все свои документы, сохраненные к iCloud. Сохраните ответ как пользовательскую настройку.
На основе этого предпочтения приложение пишет файлы документов или в песочницу локального приложения или в каталог контейнера iCloud. (Для получения дополнительной информации см. Движущиеся Документы и от Хранения iCloud.) Приложение должно представить переключатель в приложении Настроек, позволяющем пользователям переместить документы между локальным хранением и хранением iCloud.
Создание нового документа
Объект документа (т.е. экземпляр Вашего пользовательского UIDocument
подкласс), должен иметь файл URL, определяющий местоположение файла документа или в песочнице локального приложения или в каталоге контейнера iCloud, какой бы ни предпочтение пользователя. Кроме того, новому документу можно дать имя. Следующее обсуждает инструкции и процедуры, связанные для регистрации URLs, названий документа и создания новых документов.
Имя файла документа по сравнению с названием документа
UIDocument
класс принимает корреспонденцию между именем файла документа и названием документа (также известный имя дисплея). По умолчанию, UIDocument
хранит имя файла как значение localizedName
свойство. Однако приложение не должно требовать, чтобы пользователь обеспечил имя файла документа или имя дисплея, когда он или она создает новый документ.
Для Вашего приложения необходимо разработать некоторое соглашение для того, чтобы автоматически генерировать имена файлов для новых документов. Некоторые предложения:
Генерируйте UUID (универсально уникальный идентификатор) для каждого документа, дополнительно со специализированным префиксом.
Генерируйте метку времени (дата и время) каждого документа, дополнительно со специализированным префиксом.
Используйте последовательную систему нумерации, например: “Примечания 1”, “Примечания 2”, и т.д.
Для документа (дисплей) называют, Вы могли бы первоначально использовать имя файла документа, если это целесообразно (такой как с “Примечаниями 1”). Или, если документ содержит текст, и пользователь вводит некоторый текст в документе, Вы могли бы использовать первую строку (или некоторая часть первой строки) как имя дисплея. Ваше приложение может дать пользователям некоторый способ настроить название документа после того, как был создан документ.
Создание файла URL и сохранение файла документа
Вы не можете создать объект документа без правильного файла URL. Файл URL имеет три части интереса: путь к Documents
каталог в предпочтительном расположении документа пользователя, имени файла документа и расширении файла документа. Можно получить URL, представляющий путь к Documents
каталог в локальном приложении играет в песочнице через метод, такой как тот в Имени файла Документа По сравнению с Названием документа.
Перечисление 4-1 , Получающее URL к приложению Documents
каталог в локальной тестовой среде
-(NSURL*)localDocumentsDirectoryURL { |
static NSURL *localDocumentsDirectoryURL = nil; |
if (localDocumentsDirectoryURL == nil) { |
NSString *documentsDirectoryPath = [NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, |
NSUserDomainMask, YES ) objectAtIndex:0]; |
localDocumentsDirectoryURL = [NSURL fileURLWithPath:documentsDirectoryPath]; |
} |
return localDocumentsDirectoryURL; |
} |
Расширение файла должно быть тем, которое Вы указали для типа документа (см. Создание и Конфигурирование Проекта). Можно объявить, что глобальная строка представляет расширение. Например:
static NSString *FileExtension = @"imageNotes"; |
Заключительная часть файла документа URL является компонентом имени файла. Как Имя файла Документа По сравнению с Названием документа объясняет, приложение должно первоначально генерировать имя файла документа согласно некоторому соглашению, которое целесообразно для приложения. Это сгенерированное имя файла может использоваться в качестве названия документа, или первая строка (или часть этого) может использоваться в качестве названия документа. Приложение может дать пользователю опцию настройки названия документа после того, как был создан объект документа.
После конкатенации базового URL, имени файла документа и расширения файла, можно выделить экземпляр пользовательского UIDocument
разделите на подклассы и инициализируйте его с initWithFileURL:
метод, передающий в созданном файле URL. Последний шаг в создании нового документа должен сохранить его к предпочтительному расположению хранения документов (даже при том, что нет никакого содержания в этой точке). Как проиллюстрировано путем Установки Предпочтительного Места хранения для Файлов документов, Вы делаете это путем вызова saveToURL:forSaveOperation:completionHandler:
метод на объекте документа.
Перечисление 4-2 , Сохраняющее новый документ к файловой системе
-(void)viewWillAppear:(BOOL)animated { |
[super viewWillAppear:animated]; |
if (_createFile) { |
[self.document saveToURL:self.document.fileURL |
forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success) { |
if (success) |
_textView.text = self.document.text; |
}]; |
_createFile = NO; |
} |
// ..... |
} |
Параметр сохранять-работы вызова метода должен быть UIDocumentSaveForCreating
. Заключительный параметр вызова является завершением hander: блок, вызывающийся после работы сохранения, завершает. Параметр блока говорит Вам, успешно выполнилась ли работа. Если это действительно успешно выполнялось, этот код присваивает текст документа text
свойство текстового представления, выводящего на экран содержание документа.
Открытие и закрытие документа
Открытие документа, могло бы на первый взгляд казаться, было бы довольно простой процедурой. Ваше приложение сканирует содержание Documents
каталог для файлов, имеющих расширение и подарки документа те документы пользователю для выбора. Однако, когда хранение iCloud является factored в, вещи становятся немного более сложными. Документы Вашего приложения могли быть в Documents
каталог тестовой среды приложения или они могли быть в Documents
каталог каталога контейнера iCloud.
Обнаружение документов приложения
Для получения списка документов приложения в хранении iCloud выполните запрос метаданных. Запрос является экземпляром NSMetadataQuery
класс. После создания a NSMetadataQuery
объект, Вы даете ему объем и предикат. Для хранения iCloud объем должен быть NSMetadataQueryUbiquitousDocumentsScope
. Предикат NSPredicate
возразите, что, в этом случае, ограничивает поиск расширением файла. Прежде чем Вы начнете выполнять запрос, регистр для наблюдения NSMetadataQueryDidFinishGatheringNotification
и NSMetadataQueryDidUpdateNotification
уведомления. Поставка принятия метода этих уведомлений обрабатывает результаты запроса.
Перечисление 4-3 иллюстрирует, как Вы устанавливаете и выполняете запрос метаданных для получения списка документов приложения в iCloud мобильный контейнер. Метод сначала тестирует предпочтительное место хранения пользователя на документы ( documentsInCloud
свойство). Если то расположение является мобильным контейнером, оно выполняет запрос метаданных. Если расположение является тестовой средой приложения, оно выполняет итерации через содержание приложения Documents
каталог для получения названий и местоположения всех локальных файлов документов.
Перечисление 4-3 , Получающее расположения документов, хранивших локально и в хранении iCloud
-(void)viewDidLoad { |
[super viewDidLoad]; |
// set up Add and Edit navigation items here.... |
if (self.documentsInCloud) { |
_query = [[NSMetadataQuery alloc] init]; |
[_query setSearchScopes:[NSArray arrayWithObjects:NSMetadataQueryUbiquitousDocumentsScope, nil]]; |
[_query setPredicate:[NSPredicate predicateWithFormat:@"%K LIKE '*.txt'", NSMetadataItemFSNameKey]]; |
NSNotificationCenter* notificationCenter = [NSNotificationCenter defaultCenter]; |
[notificationCenter addObserver:self selector:@selector(fileListReceived) |
name:NSMetadataQueryDidFinishGatheringNotification object:nil]; |
[notificationCenter addObserver:self selector:@selector(fileListReceived) |
name:NSMetadataQueryDidUpdateNotification object:nil]; |
[_query startQuery]; |
} else { |
NSArray* localDocuments = [[NSFileManager defaultManager] contentsOfDirectoryAtPath: |
[self.documentsDir path] error:nil]; |
for (NSString* document in localDocuments) { |
[_fileList addObject:[[[FileRepresentation alloc] initWithFileName:[document lastPathComponent] |
url:[NSURL fileURLWithPath:[[self.documentsDir path] |
stringByAppendingPathComponent:document]]] autorelease]]; |
} |
} |
} |
В этом примере формат предиката @"%K LIKE '*.txt’"
, что означает возвращать все имена файлов ( NSMetadataItemFSNameKey
ключ), которые имеют расширение txt
, расширение файла файлов документов этого приложения.
После того, как начальный запрос завершает, и снова если существуют последующие обновления, метод уведомления, указанный в Перечислении 4-3 (fileListReceived
) вызывается снова. Перечисление 4-4 показывает реализацию этого метода. Если обновления запроса наступают после того, как пользователь сделал выбор, код также отслеживает текущий выбор.
Перечисление 4-4 , Собирающее информацию о документах в хранении iCloud
-(void)fileListReceived { |
NSString* selectedFileName=nil; |
NSInteger newSelectionRow = [self.tableView indexPathForSelectedRow].row; |
if (newSelectionRow != NSNotFound) { |
selectedFileName = [[_fileList objectAtIndex:newSelectionRow] fileName]; |
} |
[_fileList removeAllObjects]; |
NSArray* queryResults = [_query results]; |
for (NSMetadataItem* result in queryResults) { |
NSString* fileName = [result valueForAttribute:NSMetadataItemFSNameKey]; |
if (selectedFileName && [selectedFileName isEqualToString:fileName]) { |
newSelectionRow = [_fileList count]; |
} |
[_fileList addObject:[[[FileRepresentation alloc] initWithFileName:fileName |
url:[result valueForAttribute:NSMetadataItemURLKey]] autorelease]]; |
} |
[self.tableView reloadData]; |
if (newSelectionRow != NSNotFound) { |
NSIndexPath* selectionPath = [NSIndexPath indexPathForRow:newSelectionRow inSection:0]; |
[self.tableView selectRowAtIndexPath:selectionPath animated:NO scrollPosition:UITableViewScrollPositionNone]; |
} |
} |
Пример приложения теперь имеет массив (_fileList
) из пользовательских объектов модели, инкапсулирующих имя и файл URL каждого из документов приложения. (FileRepresentation
пользовательский класс тех объектов.) Корневой контроллер представления заполняет простое табличное представление с названиями документа
Загрузка Файлов документов от iCloud
При выполнении запроса метаданных для приобретения знаний о документах iCloud приложения, результаты запроса являются элементами заполнителя (NSMetadataItem
объекты) для файлов документов. Элементы содержат метаданные о файле, таком как его URL и его дата модификации. Файл документа не находится в каталоге контейнера iCloud.
Фактические данные для документа не загружаются, пока одно из следующего не происходит:
Ваше приложение пытается открыть или получить доступ к файлу, такой как путем вызова
openWithCompletionHandler:
.Ваше приложение вызывает
NSFileManager
методstartDownloadingUbiquitousItemAtURL:error:
загружать данные явно.
Поскольку загрузка больших файлов документов от iCloud могла бы привести к заметной задержке отображения данных документа, необходимо указать пользователю, что загрузка началась (например, покажите «загрузку» или «обновление»), и что файл не в настоящее время доступен. Удалите эту индикацию, когда завершится загрузка.
Открытие документа
Демонстрационные основанные на документе списки приложений известные документы в табличном представлении. Когда пользователь касается перечисленного документа для открытия его, UITableView
вызывает tableView:didSelectRowAtIndexPath:
метод его делегата. Реализация этого метода, показанного в Перечислении 4-5, типична для образца навигации: корневой контроллер представления выделяет следующий контроллер представления в последовательности — в этом случае, контроллер представления, представляющий данные документа — и инициализирует с существенными данными — в этом случае, файл документа URL. На основе того, является ли идиома устройства iPad или iPhone (или касание iPhone), корневой контроллер представления добавляет контроллер представления к представлению разделения или продвигает его на штабеле контроллера навигации.
Перечисление 4-5 , Отвечающее на запрос для открытия документ
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath |
{ |
[self selectFileAtIndexPath:indexPath create:NO]; |
} |
-(void)selectFileAtIndexPath:(NSIndexPath*)indexPath create:(BOOL)create |
{ |
NSArray* fileList = indexPath.section == 0 ? _localFileList : _ubiquitousFileList; |
DetailViewController* detailViewController = [[DetailViewController alloc] |
initWithFileURL:[[fileList objectAtIndex:indexPath.row] url] createNewFile:create]; |
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) { |
self.splitViewController.viewControllers = |
[NSArray arrayWithObjects:self.navigationController, detailViewController, nil]; |
} |
else { |
[self.navigationController pushViewController:detailViewController animated:YES]; |
} |
[detailViewController release]; |
} |
В его методе инициализатора (не показанный), контроллер представления документа (DetailViewController
в примере), выделяет экземпляр UIDocument
разделите на подклассы и инициализирует его путем вызова initWithFileURL:
метод, передающий в файле URL. Это присваивает недавно создаваемый объект документа a document
свойство.
Последний шаг в открытии документа должен вызвать openWithCompletionHandler:
метод на UIDocument
объект; контроллер представления документа в нашем примере приложения призывает этот метод viewWillAppear:
, как показано в Перечислении 4-6. Код проверяет состояние документа, чтобы проверить, что документ закрывается прежде, чем попытаться открыть его — нет никакой потребности открыть уже открытый документ.
Перечисление 4-6 , Открывающее документ
-(void)viewWillAppear:(BOOL)animated { |
[super viewWillAppear:animated]; |
if (_createFile) { |
[self.document saveToURL:self.document.fileURL forSaveOperation:UIDocumentSaveForCreating |
completionHandler:^(BOOL success) { |
_textView.text = self.document.text; |
}]; |
_createFile = NO; |
} |
else { |
if (self.document.documentState & UIDocumentStateClosed) { |
[self.document openWithCompletionHandler:nil]; |
} |
} |
} |
Когда openWithCompletionHandler:
вызывается, UIDocument
считывает данные из файла документа, и сам объект документа создает свои объекты модели из данных. В конце этой последовательности действий, обработчика завершения openWithCompletionHandler:
метод выполняется. Несмотря на то, что контроллер представления в примере не реализует блок завершения, обработчик завершения иногда используется для присвоения данных документа представлению документа или представлениям для дисплея. (Для вспоминания, что DetailViewController
делает вместо этого для обновления представлений документа, видят Распечатку 3-4 и сопутствующий текст.)
Закрытие документа
Для закрытия документа отправьте a closeWithCompletionHandler:
метод к объекту документа. Этот метод сохраняет данные документа, при необходимости, и затем выполняет обработчик завершения в собственном параметре.
Хорошее время для закрытия документа - когда контроллер представления документа отклонен, такой как тогда, когда пользователь касается кнопки «Назад». Прежде чем представление контроллера представления исчезает, viewWillDisappear:
метод вызывается. Ваш подкласс контроллера представления может переопределить этот метод для вызова closeWithCompletionHandler:
на объекте документа, как показано в Перечислении 4-7.
Перечисление 4-7 , Закрывающее документ
-(void)viewDidDisappear:(BOOL)animated { |
[super viewDidDisappear:animated]; |
[self.document closeWithCompletionHandler:nil]; |
} |
Движущиеся Документы и от Хранения iCloud
Как отмечено в Установке Предпочтительного Места хранения для Файлов документов, приложение должно дать его пользователям опцию того, чтобы хранить все документы в локальной файловой системе (тестовая среда приложения) или в iCloud (контейнерный каталог). Это хранит эту опцию как пользовательскую настройку и относится к этому предпочтению при сохранении и вводным документам. Когда пользователь изменяет предпочтение, приложение должно переместить все файлы документов в тестовую среду приложения к iCloud или переместить все файлы в другое направление, в зависимости от природы изменения.
Получение Расположения Каталога Контейнера iCloud
Когда Вы перемещаете файл документа от локального хранения до Documents
подкаталог каталога контейнера iCloud, его имя файла неизменно. Единственная часть отличающегося пути URL ФАЙЛА является продвижением части до Documents
. Для получения той части пути необходимо вызвать URLForUbiquityContainerIdentifier:
метод NSFileManager
. Большую часть времени Вы передаете nil
к этому методу для получения контейнерного каталога приложения по умолчанию. Если Ваши поддержки приложений многократные контейнеры, можно запросить контейнеры явно путем передачи в строке с соответствующим идентификатором контейнера iCloud — связь команды ID и комплект приложений ID, разделенный периодом. Эти контейнерные строки идентификатора являются теми же, которые Вы указываете в поле Identifier Вашего представления Summary цели приложения в XCode. Это - хорошая идея объявить строковую константу для каждого из контейнерных идентификаторов Вашего приложения, как в этом примере:
static NSString *UbiquityContainerIdentifier = @"A93A5CM278.com.acme.document.billabong"; |
Эти два метода в Перечислении 4-8 получают идентификатор контейнера iCloud и добавляют “/ Документы” ему.
Перечисление 4-8 , Получающее каталог URL контейнера iCloud
-(NSURL*)ubiquitousContainerURL { |
return [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil]; |
} |
-(NSURL*)ubiquitousDocumentsDirectoryURL { |
return [[self ubiquitousContainerURL] URLByAppendingPathComponent:@"Documents"]; |
} |
Перемещение Документа Хранению iCloud
Программно, Вы помещаете документ в хранение iCloud путем вызова NSFileManager
метод setUbiquitous:itemAtURL:destinationURL:error:
. Этот метод требует файла URL файла документа в тестовой среде приложения (источник URL) и целевого файла URL файла документа в каталоге контейнера iCloud приложения. Первый параметр принимает булево значение, которое должно быть YES
.
Метод в Перечислении 4-9 иллюстрирует, как переместить файл документа от тестовой среды приложения до хранения iCloud. В примере приложения, когда предпочтительное место хранения пользователя (iCloud или локальный) изменения, этот метод вызывают для каждого файла документа в тестовой среде приложения. Существует примерно три части к этому методу:
Составьте источник URL и целевой URL.
На вторичной очереди отгрузки: Вызовите
setUbiquitous:itemAtURL:destinationURL:error:
метод и кэш результат, булево значение (success
) это указывает, переместился ли файл документа успешно в каталог контейнера iCloud.На основной очереди отгрузки: Если вызов успешно выполняется, обновите объекты модели документа и его представление тех объектов; если вызов не успешно выполняется, зарегистрируйте ошибку (или иначе обработайте ее).
Перечисление 4-9 , Перемещающее файл документа в хранение iCloud от локального хранения
- (void)moveFileToiCloud:(FileRepresentation *)fileToMove { |
NSURL *sourceURL = fileToMove.url; |
NSString *destinationFileName = fileToMove.fileName; |
NSURL *destinationURL = [self.documentsDir URLByAppendingPathComponent:destinationFileName]; |
dispatch_queue_t q_default; |
q_default = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); |
dispatch_async(q_default, ^(void) { |
NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease]; |
NSError *error = nil; |
BOOL success = [fileManager setUbiquitous:YES itemAtURL:sourceURL |
destinationURL:destinationURL error:&error]; |
dispatch_queue_t q_main = dispatch_get_main_queue(); |
dispatch_async(q_main, ^(void) { |
if (success) { |
FileRepresentation *fileRepresentation = [[FileRepresentation alloc] |
initWithFileName:fileToMove.fileName url:destinationURL]; |
[_fileList removeObject:fileToMove]; |
[_fileList addObject:fileRepresentation]; |
NSLog(@"moved file to cloud: %@", fileRepresentation); |
} |
if (!success) { |
NSLog(@"Couldn't move file to iCloud: %@", fileToMove); |
} |
}); |
}); |
} |
Удаление Документа от Хранения iCloud
Перемещать файл документа от каталога контейнера iCloud до Documents
каталог тестовой среды приложения, выполните ту же процедуру, описанную в Перемещении Документа Хранению iCloud, кроме переключателя источник URL (теперь файл документа в каталоге контейнера iCloud) и целевой URL (теперь файл документа в тестовой среде приложения). Кроме того, первый параметр setUbiquitous:itemAtURL:destinationURL:error:
метод должен теперь быть NO
. Перечисление 4-10 показывает метод, реализовывая эту процедуру; это вызывают для каждого файла в каталоге контейнера iCloud, перемещая его в тестовую среду приложения.
Перечисление 4-10 , Перемещающее файл документа от хранения iCloud до локального хранения
- (void)moveFileToLocal:(FileRepresentation *)fileToMove { |
NSURL *sourceURL = fileToMove.url; |
NSString *destinationFileName = fileToMove.fileName; |
NSURL *destinationURL = [self.documentsDir URLByAppendingPathComponent:destinationFileName]; |
dispatch_queue_t q_default; |
q_default = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); |
dispatch_async(q_default, ^(void) { |
NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease]; |
NSError *error = nil; |
BOOL success = [fileManager setUbiquitous:NO itemAtURL:sourceURL destinationURL:destinationURL |
error:&error]; |
dispatch_queue_t q_main = dispatch_get_main_queue(); |
dispatch_async(q_main, ^(void) { |
if (success) { |
FileRepresentation *fileRepresentation = [[FileRepresentation alloc] |
initWithFileName:fileToMove.fileName url:destinationURL]; |
[_fileList removeObject:fileToMove]; |
[_fileList addObject:fileRepresentation]; |
NSLog(@"moved file to local storage: %@", fileRepresentation); |
} |
if (!success) { |
NSLog(@"Couldn't move file to local storage: %@", fileToMove); |
} |
}); |
}); |
} |
Контроль изменений состояния документа и ошибок из-за неправильного обращения
Документ может пройти через различные состояния во время своей жизни во время выполнения. Состояние может сказать Вам, сталкивается ли документ с ошибкой, конфликтом версий или некоторым другим условием, которое не нормально. UIDocument
объявляет константы (типа UIDocumentState
) представлять состояния документа и наборы documentState
свойство с одной из этих констант, когда изменение является состоянием документа, происходит. Таблица 4-1 описывает константы состояния.
Постоянное состояние документа | Что это означает |
---|---|
| Документ открыт и не испытывает конфликтов или других проблем. |
| Документ закрывается. Документ находится в этом состоянии если |
| Существуют версии документа, которые находятся в конфликте. |
| Ошибка предотвращает |
| Не в настоящее время безопасно позволить пользователям редактировать документ. |
UIDocument
также отправляет уведомление о типе UIDocumentStateChangedNotification
когда происходит изменение в состоянии документа. Ваше приложение должно наблюдать это уведомление и ответить соответственно. Метод инициализатора контроллера представления документа является хорошим местом для добавления наблюдателя, как показано в Перечислении 4-11. Наблюдатель в этом случае является контроллером представления.
Перечисление 4-11 , Добавляющее наблюдателя UIDocumentStateChangedNotification
уведомление
-(id)initWithFileURL:(NSURL*)url createNewFile:(BOOL)createNewFile { |
NSString* nibName = [[UIDevice currentDevice] userInterfaceIdiom] == |
UIUserInterfaceIdiomPad ? @"DetailViewController_iPad" : @"DetailViewController_iPhone"; |
self = [super initWithNibName:nibName bundle:nil]; |
if (self) { |
_document = [[ImageNotesDocument alloc] initWithFileURL:url]; |
// other code here.... |
[[NSNotificationCenter defaultCenter] addObserver:self |
selector:@selector(documentStateChanged) |
name:UIDocumentStateChangedNotification object:_document]; |
} |
return self; |
} |
Обязательно удалите наблюдателя из центра уведомления в классе dealloc
метод.
Когда изменения состояния документа, UIDocument
сообщения UIDocumentStateChangedNotification
уведомление и центр уведомления поставляют его путем вызова метода уведомления (documentStateChanged
в примере). В Перечислении 4-12 контроллер представления наблюдения получает текущее состояние от documentState
свойство и оценивает его. Если состояние UIDocumentStateEditingDisabled
, это скрывает клавиатуру. Если существуют конфликты между различными версиями документа (UIDocumentStateInConflict
), это выводит на экран кнопку Show Conflicts на панели инструментов представления документа. (Для получения дальнейшей информации при обработке конфликтов версии документа, посмотрите Разрешение Конфликтов Версии документа.)
Перечисление 4-12 Оценивая состояние текущего документа
-(void)documentStateChanged { |
UIDocumentState state = _document.documentState; |
[_statusView setDocumentState:state]; |
if (state & UIDocumentStateEditingDisabled) { |
[_textView resignFirstResponder]; |
} |
if (state & UIDocumentStateInConflict) { |
[self showConflictButton]; |
} |
else { |
[self hideConflictButton]; |
[self dismissModalViewControllerAnimated:YES]; |
} |
} |
Метод обработки уведомления также вызывает a setDocumentState:
метод реализован частным классом представления. Этот метод, показанный в Перечислении 4-13, изменяет другие элементы панели инструментов представления документа в зависимости от состояния документа.
Перечисление 4-13 , Обновляющее пользовательский интерфейс документа для отражения его состояние
-(void)setDocumentState:(UIDocumentState)documentState { |
if (documentState & UIDocumentStateSavingError) { |
self.unsavedLabel.hidden = NO; |
self.circleView.image = [UIImage imageNamed:@"Red"]; |
} |
else { |
self.unsavedLabel.hidden = YES; |
if (documentState & UIDocumentStateInConflict) { |
self.circleView.image = [UIImage imageNamed:@"Yellow"]; |
} |
else { |
self.circleView.image = [UIImage imageNamed:@"Green"]; |
} |
} |
} |
Если документ не мог бы быть сохранен (UIDocumentStateSavingError
), контроллер представления изменяет индикатор состояния на красный и выводит на экран Несохраненный рядом с ним. Если там конфликтуют версии документа, это делает индикатор состояния желтым (это в дополнение к кнопке Show Conflicts, упомянул ранее). Иначе, индикатор состояния является зеленым.
Удаление документа
Так же, как Вы хотите позволить пользователям создавать документ, Вы также хотите позволить им удалить выбранные документы. Удаление документа требует, чтобы Вы сделали три вещи:
Удалите файл документа из хранения (или от локальной тестовой среды или от каталога контейнера iCloud).
Удалите объекты модели, используемые для представления данных документа в памяти.
Удалите данные документа, представленные в представлении документа.
При удалении документа из хранения код должен приблизиться что UIDocument
делает для чтения и записи операций. Это должно выполнить удаление асинхронно на очереди фоновых задач, и это должно использовать координацию файла. Перечисление 4-14 иллюстрирует эту процедуру. Это диспетчеризирует задачу на очереди фоновых задач, создающей NSFileCoordinator
объект и вызовы coordinateWritingItemAtURL:options:error:byAccessor:
метод на нем. byAccessor
блок этого вызовы метода NSFileManager
метод для удаления файла, removeItemAtURL:error:
.
Перечисление 4-14 Удаляя выбранный документ
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle |
forRowAtIndexPath:(NSIndexPath *)indexPath { |
NSMutableArray* fileList = nil; |
if (indexPath.section == 0) { |
fileList = self.localFileList; |
} |
else { |
fileList = self.ubiquitousFileList; |
} |
NSURL* fileURL = [[fileList objectAtIndex:indexPath.row] url]; |
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) { |
NSFileCoordinator* fileCoordinator = [[NSFileCoordinator alloc] initWithFilePresenter:nil]; |
[fileCoordinator coordinateWritingItemAtURL:fileURL options:NSFileCoordinatorWritingForDeleting |
error:nil byAccessor:^(NSURL* writingURL) { |
NSFileManager* fileManager = [[NSFileManager alloc] init]; |
[fileManager removeItemAtURL:writingURL error:nil]; |
}]; |
}); |
[fileList removeObjectAtIndex:indexPath.row]; |
[tableView deleteRowsAtIndexPaths:[[NSArray alloc] initWithObjects:&indexPath count:1] |
withRowAnimation:UITableViewRowAnimationLeft]; |
} |
В этом примере пользователь инициировал вызов метода, когда он или она касается кнопки Delete подряд, в то время как табличное представление находится в режиме редактирования.