2016-04-19 11 views
0

Начинает работать приложение на основе основных данных на "сохранить как". Проблема, кажется, похожа на описанную в какао-Dev нить под названием «NSPersistentDocument objects "gutted" after Duplicate, Rename in 10.9»NSPsistentDocument crash on "save as"

Ключевые различия в том, что:

  • таргетировать и работать на OS X 10,10 Yosemite
  • Использование «Сохранить Как ", а не дубликат
  • Авария происходит раньше. Во время сохранения MOC

Проблема затрагивает даже самый простой NSPsistentDocument. Это было, по крайней мере, с 2014 года. Таким образом, я надеюсь, что другие столкнулись с той же проблемой и найдут решение, которое вы поделитесь.

В моем sample project используется единое целое с одним атрибутом. Он имеет представление таблицы для отображения всех экземпляров объекта и кнопки для создания нового. Я отклонился от шаблона по умолчанию, чтобы отключить autosavesInPlace.

Шаги по воспроизведению аварии являются:

  1. Построить и запустить на Йосемити. Ошибка, кажется, был зафиксирован в Эль CAPITAN
  2. Создать новый документ
  3. Вставьте новый объект
  4. Сохранить документ
  5. Закройте документ
  6. Повторно откройте документ
  7. Изменить значение атрибута в таблице
  8. Используйте «Сохранить как» для сохранения под новым именем

На OS X Yosemite это всегда падает со следующей трассировкой:

_propertyAtIndexForEntityDescription() 
snapshot_get_value_as_object() 
-[NSManagedObject(_NSInternalMethods) _validatePropertiesWithError:]() 
-[NSManagedObject(_NSInternalMethods) _validateForSave:]() 
-[NSManagedObject validateForUpdate:]() 
-[NSManagedObjectContext(_NSInternalAdditions) _validateObjects:forOperation:error:exhaustive:forSave:]() 
-[NSManagedObjectContext(_NSInternalAdditions) _validateChangesForSave:]() 
-[NSManagedObjectContext(_NSInternalChangeProcessing) _prepareForPushChanges:]() 
-[NSManagedObjectContext save:]() 
-[NSPersistentDocument writeToURL:ofType:forSaveOperation:originalContentsURL:error:]() 
-[NSDocument _writeSafelyToURL:ofType:forSaveOperation:forceTemporaryDirectory:error:]() 
-[NSDocument _writeSafelyToURL:ofType:forSaveOperation:error:]() 
-[NSDocument writeSafelyToURL:ofType:forSaveOperation:error:]() 
-[NSPersistentDocument writeSafelyToURL:ofType:forSaveOperation:error:]() 
__66-[NSDocument saveToURL:ofType:forSaveOperation:completionHandler:]_block_invoke_22353() 
__66-[NSDocument saveToURL:ofType:forSaveOperation:completionHandler:]_block_invoke2350() 
__66-[NSDocument saveToURL:ofType:forSaveOperation:completionHandler:]_block_invoke_22222() 
__110-[NSFileCoordinator(NSPrivate) _coordinateReadingItemAtURL:options:writingItemAtURL:options:error:byAccessor:]_block_invoke428() 
-[NSFileCoordinator(NSPrivate) _invokeAccessor:orDont:andRelinquishAccessClaim:]() 
-[NSFileCoordinator(NSPrivate) _coordinateReadingItemAtURL:options:writingItemAtURL:options:error:byAccessor:]() 
-[NSDocument _fileCoordinator:coordinateReadingContentsAndWritingItemAtURL:byAccessor:]() 
-[NSDocument _fileCoordinator:asynchronouslyCoordinateReadingContentsAndWritingItemAtURL:byAccessor:]() 
__66-[NSDocument saveToURL:ofType:forSaveOperation:completionHandler:]_block_invoke2221() 
-[NSDocument _prepareToSaveToURL:forSaveOperation:completionHandler:]() 
__66-[NSDocument saveToURL:ofType:forSaveOperation:completionHandler:]_block_invoke() 
-[NSDocument continueFileAccessUsingBlock:]() 
-[NSDocument _performFileAccessOnMainThread:usingBlock:]() 
-[NSDocument performAsynchronousFileAccessUsingBlock:]() 
-[NSDocument saveToURL:ofType:forSaveOperation:completionHandler:]() 
__85-[NSDocument saveToURL:ofType:forSaveOperation:delegate:didSaveSelector:contextInfo:]_block_invoke_2() 
-[NSDocument _commitEditingThenContinue:]() 
__62-[NSPersistentDocument _documentEditor:didCommit:withContext:]_block_invoke() 

Edit 1. Возможным обходным путем:

я могу пропатчить вокруг аварии, предотвращая оригинальный контекст управляемого объекта из спасаемых во время операция «сохранить как». После «Сохранить как» я сразу закрою существующий документ и снова открою документ из нового местоположения. Все это очень уродливо и может нарушить другое поведение NSPsistentDocument.

Edit 2. Над обходного теряет несохраненные изменения

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

Edit 3. Gutted снимок

К тому времени старый контекст управляемый объект пытается сохранить изменения в новый файл, объект снимка не знает больше его сущность <_CDSnapshot_Entity_: 0x600001f3cfd0> (entity: (null); id: 0x40000b <x-coredata://83B64FD3-B5B9-44CB-976D-54C0326FDFF5/Entity/p1> ; data: (null)). Я не вижу поддержки переменной экземпляра -[_CDSnapshot entity].Я предполагаю, что он должен найти это из идентификатора объекта.

+0

Теперь это становится странным: образец проекта падает на одной машине El Capitan, но не на другой. На машине, где приложение-образец не падает, при создании «пустой записи» создается пустой документ. –

+0

Я вижу, что сохранение вызывает открытый метод 'validateForUpdate:'. Интересно, что произойдет, если вы вызовете это прямо на объект документа. –

+0

Нет ошибки, если я вызываю 'validateForUpdate:' перед вызовом '[super writeToURL: ofType: forSaveOperation: originalContentsURL: error:]'. Я думаю, что проблема возникает, когда при создании нового контекста вызываемого объекта возникает вызов. Похоже, что свойства управляемых объектов больше недоступны в этой точке. –

ответ

0

У меня возникло обходное решение, которое, похоже, работает для моего прецедента.

- (BOOL)writeToURL:(NSURL *)absoluteURL 
      ofType:(NSString *)typeName 
    forSaveOperation:(NSSaveOperationType)saveOperation 
originalContentsURL:(NSURL *)absoluteOriginalContentsURL 
      error:(NSError **)error 
{ 
    if ((saveOperation == NSSaveAsOperation) && (absoluteOriginalContentsURL != nil)) { 
     NSFileManager *fileManager = [NSFileManager defaultManager]; 

     if (![fileManager copyItemAtURL:absoluteOriginalContentsURL toURL:absoluteURL error:error]) { 
      return NO; 
     } 

     NSManagedObjectContext *managedObjectContext = self.managedObjectContext; 
     NSPersistentStoreCoordinator *persistentStoreCoordinator = managedObjectContext.persistentStoreCoordinator; 
     NSPersistentStore *store = [persistentStoreCoordinator persistentStoreForURL:absoluteOriginalContentsURL]; 

     [persistentStoreCoordinator setURL:absoluteURL forPersistentStore:store]; 

     if (![managedObjectContext save:error]) { 
      return NO; 
     } 

     return YES; 
    } 

    return [super writeToURL:absoluteURL 
          ofType:typeName 
        forSaveOperation:saveOperation 
       originalContentsURL:absoluteOriginalContentsURL 
           error:error]; 
} 

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

NSPersistentDocument заботится о создании временного URL-адреса, переданного как absoluteURL, перемещает сохраненный файл в новое место и вызывает setFileURL: после завершения сохранения.

Я отключил ведение журнала в хранилище SQLite, поддерживая документ. Поэтому мне нужно только скопировать один файл по адресу absoluteOriginalContentsURL.