Как убедиться, что UIManagedDocument готов до вызова метода NSFetchedResultsController?

Я полностью застрял на этом. Моя основная проблема в том, что мой:

   - (NSFetchedResultsController *)fetchedResultsController

Метод дает сбой, когда пытается прочитать мою сущность Core Core, так как manageObjectContext / UIManagedDocument равен нулю. На данный момент я думаю, что это потому, что мой UIManagedDocument не открыт/не готов. Итак, последние 3 часа я пытался сделать так, чтобы мой метод делегата не запускался, пока документ не будет открыт.

Это код, который я использую для получения документа:

      if (!self.document) {
    [[CATManagedDocumentHandler sharedDocumentHandler] performWithDocument:^(UIManagedDocument *document) {
        self.document = document;         
    }];
} 

Это отлично работает в любом другом месте моего приложения, но кажется, что процесс открытия недостаточно быстр для методов делегата в моем tableView.

Ссылки, которые я просмотрел до сих пор:

http://omegadelta.net/2011/05/10/how-to-wait-for-ios-methods-with-completion-blocks-to-finish/

Выполнение блока кода вместо @selector

О вызове dispatch_queue_t и dispatch_sync

Grand Central Dispatch (GCD) vs. PerformSelector - нужен лучшее объяснение

GCD для выполнения задачи в основном потоке

iOS — как получить уведомление, когда поток (использующий GCD) завершает свою работу

Я пробовал: блокировать основной поток, пока не получу NSNotification (настроенный в CATManagedDocumentHandler) и блокировать основной поток, пока не получу обратный вызов блока.

Ни один из них не работает. Мое приложение просто зависает. Я думаю об этом неправильно? Как я могу заставить метод делегата ждать, пока мой документ не будет открыт/готов? Или есть другой подход, который я должен использовать с этим?

Спасибо

Карл.


person Carl Taylor    schedule 08.12.2012    source источник


Ответы (1)


хорошо, когда ваше приложение впервые запускается, я бы посоветовал проверить, 1. существует ли ваша база данных (если это не так, вы выделяете ее для инициализации) и 2. если документ не существует (на диске), закрыт или открыт .

вот как вы могли бы это сделать:

похоже, что вы используете синглтон для своей базы данных, поэтому, когда появится ваш первый контроллер представления, проверьте, был ли выделен управляемый документ, поэтому в ViewWillAppear:

if (!dataBase)
{
        NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
        url = [url URLByAppendingPathComponent:@"Your DB Name"];
        self.dataBase=[[UIManagedDocument alloc]initWithFileUrl:url];
}

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

поэтому вы проверяете здесь 3 случая: не существует

if (![[NSFileManager defaultManager]fileExistsAtPath:[yourManagedDocumentFromSingleton.fileUrl path])
{
   [[NSFileManager defaultManager]fileExistsAtPath:[yourManagedDocumentFromSingleton saveToUrl:[[NSFileManager defaultManager]fileExistsAtPath:[yourManagedDocumentFromSingleton.fileUrl forSaveOperation:UIDocumentSaveForCreating completionHandler: 
^(BOOL success){ now you can use your uidocument and its managed object context}];
    }

если файл существует, но закрыт:

else if (yourManagedDocumentFromSingleton.documentState==UIDocumentStateClosed)
{
[yourManagedDocumentFromSingleton openWithCompletionHandler:
^(BOOL success) {use your document here}];
}

наконец, если документ уже открыт, просто используйте его:

else if (yourManagedDocumentFromSingleton.documentState=UIDocumentStateNormal)
{
//do whatever with the document
}

важно отметить, что UIDocument не является потокобезопасным. Поэтому его нужно использовать и проверять в том же потоке, в котором он был создан (предположительно здесь основной поток). В противном случае это не сработает.

Я не знаю точную структуру вашего контроллера представления или синглтона, но если вы выполните следующие шаги, это сработает.

PS. Также убедитесь, что после того, как ваш документ запущен и работает, и вы добавляете в него или удаляете элементы, сохраняйте его после каждой операции, чтобы ваш NSFetchedResultsController обновлялся. В CoreData есть автосохранение, но я обнаружил, что мне приходилось сохранять вручную, чтобы все работало правильно. Вы можете сохранить с помощью (из предыдущего метода):

forSaveOperation:UIDocumentSaveForOverwriting
person Live2Enjoy7    schedule 08.12.2012
comment
спасибо за ваш ответ и усилия в ответ. Теперь мне удалось открыть и подготовить мой документ... но, как ни странно, когда я делаю запрос на выборку... я не могу установить свое 'entityName'... у меня никогда не было этого раньше... это просто происходит назад с «executeFetchRequest: ошибка: запрос на выборку должен иметь объект». - person Carl Taylor; 08.12.2012
comment
skydrive.live.com/ - person Carl Taylor; 08.12.2012
comment
как вы можете видеть из приведенной выше ссылки, я явно устанавливаю Entity.. это также существует и является правильным именем из моей модели данных... - person Carl Taylor; 08.12.2012
comment
... и просто хочу отметить: я только что проверил загрузку объекта на предыдущем экране. Выходит без проблем.. - person Carl Taylor; 08.12.2012
comment
похоже, вы не устанавливаете предикат... действительно. поэтому вам нужен предикат, кроме sortDescriptor. Предикат — это то, что говорит, какие вещи нужно извлечь из объекта, который вы запрашиваете. как только вы создаете выборку, вы устанавливаете предикат, например: fetchRequest.predicate=[NSPredicate predicateWithFormat:@yourEntityAttribute=%@, someAttributeYouWant]; существует много форматов предикатов, поэтому вы можете иметь очень подробные запросы. Проверьте документацию для NSPredicate - person Live2Enjoy7; 09.12.2012