Метод «Сохранить как …» в приложении Core Data

#cocoa #core-data

#cocoa #core-data

Вопрос:

Компакт-диск стал для меня огромным испытанием, и мне еще многое предстоит сделать, но любая помощь в следующем может помочь мне снять текущий груз со своих плеч!

Я пытаюсь написать метод, который реализует «Сохранить как ..» для пользователя в моем приложении CD.

Пока у меня есть:

 [saveAsPanel beginSheetModalForWindow:window completionHandler:^(NSInteger userResult)
{
if (userResult == NSOKButton) {
    NSPersistentStoreCoordinator *psc = [self persistentStoreCoordinator];
    NSURL *oldURL = [self URLOfInternalStore]; //returns the current store's URL
    NSURL *newURL = [saveAsPanel URL];
    NSError *error = nil;
    NSPersistentStore *oldStore = [psc persistentStoreForURL:oldURL];
    NSPersistentStore *sqLiteStore = [psc migratePersistentStore:oldStore
                                                           toURL:newURL
                                                         options:nil
                                                        withType:NSXMLStoreType
                                                           error:amp;error];
}
}];
  

К сожалению, я просто получаю сообщение об ошибке:

Постоянное хранилище объекта недоступно из координатора этого NSManagedObjectContext.

Должен ли я «удалить», а затем «addPersistentStore …», чтобы обновить его до нового URL? Документы, похоже, предполагают, что все будет обработано с помощью метода ‘migrate’.

Заранее спасибо!

Редактировать:

Хорошо, хорошо, я придумал свой собственный «грязный» метод. Я могу представить, что это не одобренный способ выполнения действий, но ошибок не возникает, и приложение всегда работает должным образом (я тоже не часто могу это сказать!):

         -(IBAction)saveAsAction:(id)sender
    {
        NSSavePanel *saveAsPanel = [NSSavePanel savePanel];
        [saveAsPanel beginSheetModalForWindow:window completionHandler:^(NSInteger userResult)
        {
        if (userResult == NSOKButton) {
            [self saveAction:@"saveAsCalling"];
            NSURL *newURL = [saveAsPanel URL];
            NSError *error = nil;
            [[NSFileManager defaultManager] copyItemAtURL:[NSURL fileURLWithPath:internalStore] toURL:newURL error:amp;error];
//internalStore is a hard-wired NSString that holds the path to the bundle's database
        }
        }];
    }

    -(IBAction)loadAction:(id)sender
    {
        NSOpenPanel *loadPanel = [NSOpenPanel openPanel];
        [loadPanel beginSheetModalForWindow:window completionHandler:^(NSInteger userResult)
         {
             if (userResult == NSOKButton) {
                 [self saveAction:@"loadCalling"];
                 NSURL *newURL = [loadPanel URL];
                 NSURL *oldURL = [NSURL fileURLWithPath:internalStore];
                 NSError *error = nil;
                 NSPersistentStoreCoordinator *psc = [SELF_MOC persistentStoreCoordinator];
                 [psc removePersistentStore:[[self persistentStoreCoordinator] persistentStoreForURL:oldURL] error:amp;error];
                 [psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:newURL options:nil error:amp;error];
                 [[NSFileManager defaultManager] removeItemAtURL:oldURL error:amp;error];
                 [[NSFileManager defaultManager] copyItemAtURL:newURL toURL:oldURL error:amp;error];
                 [psc removePersistentStore:[[self persistentStoreCoordinator] persistentStoreForURL:newURL] error:amp;error];
                 [psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:oldURL options:nil error:amp;error];
             }
         }];
    }
  

Основное рассуждение таково: чтобы выполнить «SaveAs …», я просто копирую файл SQLLite store в mainBundle туда, где пользователь выберет, и переименовываю его в то, что они хотят — согласно предложению TechZen.

Чтобы выполнить «загрузку», я сначала удаляю PersistentStore из файла пакета, добавляю тот, который только что выбрал пользователь. Удалите хранилище пакетов (которое теоретически сейчас не используется), а затем скопируйте выбранный пользователем вариант обратно в пакет. Наконец, выполняются две операции remove и addPersistentStore, чтобы указать приложению обратно на файл его пакета, который теперь выбирается пользователем.

Надеюсь, это имеет смысл. Если у кого-нибудь есть какие-либо мысли о том, насколько это непрофессиональная методология, то, пожалуйста — будьте добры, поскольку я довольно новичок — дайте мне знать. Я не могу найти ничего более элегантного.

Я знаю, что Apple не нравится, когда вы используете removePersistentStore и addPersistentStore, но, как я уже сказал, никаких сообщений об ошибках не поступало (в моем реальном коде я разбросал строки NSLog повсюду, чтобы сообщить, какая ошибка содержится).

Ответ №1:

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

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

Комментарии:

1. Спасибо TechZen. Таким образом, дальнейшим способом может быть создание базовой копии файла текущего хранилища ..? Я видел онлайн-сообщение, в котором кто-то закрыл текущее окно, скопировал файл sql, а затем снова открыл окно приложения. Они признали, что это не элегантно!

2. Да, простое копирование постоянного хранилища привело бы к тому же, что и Save as...

3. Спасибо TechZen, я только что увидел ваш комментарий после того, как опубликовал свою правку.

4. Есть одно важное различие между «Сохранить как …» и копией постоянного хранилища. При выполнении первого Core Data выполнит проверку достоверности каждого объекта в хранилище. Если критерии проверки со временем изменились в вашем приложении, это может привести к новым ошибкам проверки для вашего пользователя.