I have a document-based Cocoa app using CoreData which can import large amounts of data. Since this import takes some time I do it in the background, but since NSManagedObjectContext is not thread save I used the persistentStoreCoordinator of the managedObjectContext of the document to create a new NSManagedObjectContext in the background thread. Now, when the import is finished I save the background managedObjectContext to notify the document's main-thread managedObjectContext of the changes and merge them. As far as I understand it, this is how one is supposed to do concurrency using CoreData.

But sometimes, the persistentStoreCoordinator does not have a persistentStore when I call [managedObjectContex save:] which causes the save to fail and the app to crash. I'm using autosave and all (basically a mostly unmodifed NSPersistentDocument on OS X 10.8) so I assumed that I don't have to care about how it is saved and it would "just work".

Apparently, this is not the case. I tried forcing an autosave operation, hoping that this would create a persistentStore by calling [self autosaveDocumentWithDelegate:self didAutosaveSelector:@selector(document:didAutosave:contextInfo:) contextInfo:nil]; at the end of windowControllerDidLoadNib: in my document subclass, but this doesn't seem to change anything. The delegate callback (- (void)document:(NSDocument *)document didAutosave:(BOOL)didAutosaveSuccessfully contextInfo:(void *)contextInfo) actually states the autosave was successful although neither any of the fileURL or related accessors returns something non-nil nor a persistentStore has been created.

I also thought about calling -(BOOL)configurePersistentStoreCoordinatorForURL:(NSURL *)url ofType:(NSString *)fileType modelConfiguration:(NSString *)configuration storeOptions:(NSDictionary *)storeOptions error:(NSError *__autoreleasing *)error myself, but I don't know what URL to use to make it behave just like a normal autosave. I checked backupFileURL, fileURL and autosavedContentsFileURL but all of them are still nil at the end of windowControllerDidLoadNib:. As a matter of fact, they are even nil after writeToURL:... and configurePersistentStoreCoordinatorForURL:... have been called, so I don't have a clue how to get a "correct" URL.

To better understand how and when a persistentStore is created I have set breakpoints in writeToURL:... and configurePersistentStoreCoordinatorForURL:.... I noticed that configurePersistentStoreCoordinatorForURL: is called when the application looses frontmost status. But when I just create a new document and try importing something right after it was created (without first switching to another app to cause the persistentStore to be created) it crashes. If I switch to another app, the store is created and everything works fine. By the way, the URL used for the persistentStore created this way is always somewhere in the temp directory.

Am I doing something wrong? Don't I have to call [managedObjectContext save:] to notify the other managedObjectContext of the changes? How can I force the document to create its temporary persistentStore? Why doesn't the call to autosaveDocumentWithDelegate:... actually save the document (and thus create a persistentStore)?

Related:

有帮助吗?

解决方案

I solved a similar problem: I need to generate permanent Object IDs, which require the presence of a persistent store. Like you point out, untitled documents that haven't yet been autosaved don't have persistent stores.

This abbreviated snippet is from my NSWindowController subclass:

- (void) awakeFromNib {
    //hacky way to get an autosave to generate an NSPersistentStore.
    GSNativeDocument *doc = self.document;
    [doc updateChangeCount:NSChangeDone];
    [doc autosaveDocumentWithDelegate:self didAutosaveSelector:@selector(document:didAutosave:contextInfo:) contextInfo:nil];
}

//called by the autosave operation started in awakeFromNib.
- (void)document:(NSDocument *)document didAutosave:(BOOL)didAutosaveSuccessfully contextInfo:(void *)contextInfo
{
    GSNativeDocument *doc = self.document;
    [doc updateChangeCount:NSChangeUndone];
}

Why does updating the change count create a "real" autosave, when every other way to induce an autosave doesn't? I have no clue. I've filed this bug with Apple in early January and posted in the dev forums, but they have not answered.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top