Implement file wrapper for CoreData storage
This commit is contained in:
parent
7c64c928bf
commit
0916b50bf4
|
@ -7,8 +7,31 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#import "MADocument.h"
|
#import "MADocument.h"
|
||||||
|
#import "MAFolder.h"
|
||||||
|
|
||||||
@implementation MADocument
|
#pragma mark NSPersistentDocument file URL hook
|
||||||
|
|
||||||
|
/* Adapted from NSPersistentDocumentFileWrappers */
|
||||||
|
/*
|
||||||
|
We need to bypass what NSPersistentDocument does in setFileURL:, but we do want to use the functionality provided by NSDocument's implementation of that method. To achieve this, we create a simple category on NSPersistentDocument with methods that will call the NSDocument version of the method. Then, our subclass will call the category method where it would normally simply call the super implementation.
|
||||||
|
*/
|
||||||
|
@interface NSPersistentDocument (FileWrapperSuport)
|
||||||
|
|
||||||
|
- (void)simpleSetFileURL:(NSURL *)fileURL;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation NSPersistentDocument (FileWrapperSuport)
|
||||||
|
|
||||||
|
// Forwards the message to NSDocument's setFileURL: (skips NSPersistentDocument's implementation).
|
||||||
|
- (void)simpleSetFileURL:(NSURL *)fileURL {
|
||||||
|
[super setFileURL:fileURL];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark MADocument
|
||||||
|
|
||||||
- (id)init
|
- (id)init
|
||||||
{
|
{
|
||||||
|
@ -20,6 +43,14 @@
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
This is the name of the Core Data store file contained within the document package.
|
||||||
|
You can change this whatever you want -- the user will not see this file.
|
||||||
|
*/
|
||||||
|
static NSString *StoreFileName = @"MediannoDB.sql";
|
||||||
|
|
||||||
|
@implementation MADocument
|
||||||
|
|
||||||
- (NSString *)windowNibName
|
- (NSString *)windowNibName
|
||||||
{
|
{
|
||||||
// Override returning the nib file name of the document
|
// Override returning the nib file name of the document
|
||||||
|
@ -38,4 +69,138 @@
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark URL management
|
||||||
|
|
||||||
|
/*
|
||||||
|
Returns the URL for the wrapped Core Data store file. This appends the StoreFileName to the document's path.
|
||||||
|
*/
|
||||||
|
- (NSURL *)storeURLFromPath:(NSString *)filePath {
|
||||||
|
filePath = [filePath stringByAppendingPathComponent:StoreFileName];
|
||||||
|
if (filePath != nil) {
|
||||||
|
return [NSURL fileURLWithPath:filePath];
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Sets the on-disk location. NSPersistentDocument's implementation is bypassed using the FileWrapperSupport category. The persistent store coordinator is directed to use an internal URL rather than NSPersistentDocument's default (the main file URL).
|
||||||
|
*/
|
||||||
|
- (void)setFileURL:(NSURL *)fileURL {
|
||||||
|
|
||||||
|
NSURL *originalFileURL = [self storeURLFromPath:[[self fileURL] path]];
|
||||||
|
if (originalFileURL != nil) {
|
||||||
|
NSPersistentStoreCoordinator *psc = [[self managedObjectContext] persistentStoreCoordinator];
|
||||||
|
id store = [psc persistentStoreForURL:originalFileURL];
|
||||||
|
if (store != nil) {
|
||||||
|
// Switch the coordinator to an internal URL.
|
||||||
|
[psc setURL:[self storeURLFromPath:[fileURL path]] forPersistentStore:store];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[self simpleSetFileURL:fileURL];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark Reading / Writing
|
||||||
|
|
||||||
|
/*
|
||||||
|
Overridden NSDocument/NSPersistentDocument method to open existing documents.
|
||||||
|
*/
|
||||||
|
- (BOOL)readFromURL:(NSURL *)absoluteURL ofType:(NSString *)typeName error:(NSError **)error {
|
||||||
|
|
||||||
|
BOOL success = NO;
|
||||||
|
// Create a file wrapper for the document package.
|
||||||
|
NSFileWrapper *directoryFileWrapper = [[NSFileWrapper alloc] initWithPath:[absoluteURL path]];
|
||||||
|
// File wrapper for the Core Data store within the document package.
|
||||||
|
NSFileWrapper *dataStore = [[directoryFileWrapper fileWrappers] objectForKey:StoreFileName];
|
||||||
|
|
||||||
|
if (dataStore != nil) {
|
||||||
|
NSString *path = [[absoluteURL path] stringByAppendingPathComponent:[dataStore filename]];
|
||||||
|
NSURL *storeURL = [NSURL fileURLWithPath:path];
|
||||||
|
// Set the document persistent store coordinator to use the internal Core Data store.
|
||||||
|
success = [self configurePersistentStoreCoordinatorForURL:storeURL ofType:typeName
|
||||||
|
modelConfiguration:nil storeOptions:nil error:error];
|
||||||
|
}
|
||||||
|
|
||||||
|
[directoryFileWrapper release];
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Overridden NSDocument/NSPersistentDocument method to save documents.
|
||||||
|
*/
|
||||||
|
- (BOOL)writeSafelyToURL:(NSURL *)inAbsoluteURL ofType:(NSString *)inTypeName forSaveOperation:(NSSaveOperationType)inSaveOperation error:(NSError **)outError {
|
||||||
|
|
||||||
|
BOOL success = YES;
|
||||||
|
NSFileWrapper *filewrapper = nil;
|
||||||
|
NSURL *originalURL = [self fileURL];
|
||||||
|
NSString *filePath = [inAbsoluteURL path];
|
||||||
|
|
||||||
|
// Depending on the type of save operation:
|
||||||
|
if (inSaveOperation == NSSaveAsOperation) {
|
||||||
|
|
||||||
|
// Nothing exists at the URL: set up the directory and migrate the Core Data store.
|
||||||
|
filewrapper = [[NSFileWrapper alloc] initDirectoryWithFileWrappers:nil];
|
||||||
|
// Need to write once so there's somewhere for the store file to go.
|
||||||
|
[filewrapper writeToFile:filePath atomically:NO updateFilenames:NO];
|
||||||
|
|
||||||
|
// Now, the Core Data store...
|
||||||
|
NSURL *storeURL = [self storeURLFromPath:filePath];
|
||||||
|
NSURL *originalStoreURL = [self storeURLFromPath:[originalURL path]];
|
||||||
|
|
||||||
|
if (originalStoreURL != nil) {
|
||||||
|
// This is a "Save As", so migrate the store to the new URL.
|
||||||
|
NSPersistentStoreCoordinator *coordinator = [[self managedObjectContext] persistentStoreCoordinator];
|
||||||
|
id originalStore = [coordinator persistentStoreForURL:originalStoreURL];
|
||||||
|
success = ([coordinator migratePersistentStore:originalStore toURL:storeURL options:nil withType:[self persistentStoreTypeForFileType:inTypeName] error:outError] != nil);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// This is the first Save of a new document, so configure the store.
|
||||||
|
success = [self configurePersistentStoreCoordinatorForURL:storeURL ofType:inTypeName modelConfiguration:nil storeOptions:nil error:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
[filewrapper addFileWithPath:[storeURL path]];
|
||||||
|
|
||||||
|
}
|
||||||
|
else { // This is not a Save-As operation.
|
||||||
|
// Just create a file wrapper pointing to the existing URL.
|
||||||
|
filewrapper = [[NSFileWrapper alloc] initWithPath:[inAbsoluteURL path]];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Important *
|
||||||
|
Atomicity during write is a problem that is not addressed in this sample.
|
||||||
|
See the ReadMe for discussion.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (success == YES) {
|
||||||
|
// Save the Core Data portion of the document.
|
||||||
|
success = [[self managedObjectContext] save:outError];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (success == YES) {
|
||||||
|
// Set the appropriate file attributes (such as "Hide File Extension")
|
||||||
|
NSDictionary *fileAttributes = [self fileAttributesToWriteToURL:inAbsoluteURL ofType:inTypeName forSaveOperation:inSaveOperation originalContentsURL:originalURL error:outError];
|
||||||
|
[[NSFileManager defaultManager] setAttributes:fileAttributes ofItemAtPath:[inAbsoluteURL path] error:outError];
|
||||||
|
}
|
||||||
|
[filewrapper release];
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
The revert method needs to completely tear down the object graph assembled by the document. In this case, you also want to remove the persistent store manually, because NSPersistentDocument will expect the store for its coordinator to be located at the document URL (instead of inside that URL as part of the file wrapper).
|
||||||
|
*/
|
||||||
|
- (BOOL)revertToContentsOfURL:(NSURL *)inAbsoluteURL ofType:(NSString *)inTypeName error:(NSError **)outError {
|
||||||
|
NSPersistentStoreCoordinator *psc = [[self managedObjectContext] persistentStoreCoordinator];
|
||||||
|
id store = [psc persistentStoreForURL:[self storeURLFromPath:[inAbsoluteURL path]]];
|
||||||
|
if (store) {
|
||||||
|
[psc removePersistentStore:store error:outError];
|
||||||
|
}
|
||||||
|
return [super revertToContentsOfURL:inAbsoluteURL ofType:inTypeName error:outError];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -9,69 +9,27 @@
|
||||||
<dict>
|
<dict>
|
||||||
<key>CFBundleTypeExtensions</key>
|
<key>CFBundleTypeExtensions</key>
|
||||||
<array>
|
<array>
|
||||||
<string>binary</string>
|
<string>medianno</string>
|
||||||
</array>
|
</array>
|
||||||
<key>CFBundleTypeMIMETypes</key>
|
<key>CFBundleTypeMIMETypes</key>
|
||||||
<array>
|
<array>
|
||||||
<string>application/octet-stream</string>
|
<string>application/octet-stream</string>
|
||||||
</array>
|
</array>
|
||||||
<key>CFBundleTypeName</key>
|
<key>CFBundleTypeName</key>
|
||||||
<string>Binary</string>
|
<string>MADatabase</string>
|
||||||
<key>CFBundleTypeRole</key>
|
<key>CFBundleTypeRole</key>
|
||||||
<string>Editor</string>
|
<string>Editor</string>
|
||||||
<key>LSTypeIsPackage</key>
|
<key>LSItemContentTypes</key>
|
||||||
<false/>
|
|
||||||
<key>NSDocumentClass</key>
|
|
||||||
<string>MADocument</string>
|
|
||||||
<key>NSPersistentStoreTypeKey</key>
|
|
||||||
<string>Binary</string>
|
|
||||||
</dict>
|
|
||||||
<dict>
|
|
||||||
<key>CFBundleTypeExtensions</key>
|
|
||||||
<array>
|
<array>
|
||||||
<string>sqlite</string>
|
<string>org.aereperennius.medianno-database</string>
|
||||||
</array>
|
</array>
|
||||||
<key>CFBundleTypeMIMETypes</key>
|
|
||||||
<array>
|
|
||||||
<string>application/octet-stream</string>
|
|
||||||
</array>
|
|
||||||
<key>CFBundleTypeName</key>
|
|
||||||
<string>SQLite</string>
|
|
||||||
<key>CFBundleTypeRole</key>
|
|
||||||
<string>Editor</string>
|
|
||||||
<key>LSTypeIsPackage</key>
|
<key>LSTypeIsPackage</key>
|
||||||
<false/>
|
<true/>
|
||||||
<key>NSDocumentClass</key>
|
<key>NSDocumentClass</key>
|
||||||
<string>MADocument</string>
|
<string>MADocument</string>
|
||||||
<key>NSPersistentStoreTypeKey</key>
|
<key>NSPersistentStoreTypeKey</key>
|
||||||
<string>SQLite</string>
|
<string>SQLite</string>
|
||||||
</dict>
|
</dict>
|
||||||
<dict>
|
|
||||||
<key>CFBundleTypeExtensions</key>
|
|
||||||
<array>
|
|
||||||
<string>xml</string>
|
|
||||||
</array>
|
|
||||||
<key>CFBundleTypeIconFile</key>
|
|
||||||
<string></string>
|
|
||||||
<key>CFBundleTypeMIMETypes</key>
|
|
||||||
<array>
|
|
||||||
<string>text/xml</string>
|
|
||||||
</array>
|
|
||||||
<key>CFBundleTypeName</key>
|
|
||||||
<string>XML</string>
|
|
||||||
<key>CFBundleTypeOSTypes</key>
|
|
||||||
<array>
|
|
||||||
<string>????</string>
|
|
||||||
</array>
|
|
||||||
<key>CFBundleTypeRole</key>
|
|
||||||
<string>Editor</string>
|
|
||||||
<key>LSTypeIsPackage</key>
|
|
||||||
<false/>
|
|
||||||
<key>NSDocumentClass</key>
|
|
||||||
<string>MADocument</string>
|
|
||||||
<key>NSPersistentStoreTypeKey</key>
|
|
||||||
<string>XML</string>
|
|
||||||
</dict>
|
|
||||||
</array>
|
</array>
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
<string>${EXECUTABLE_NAME}</string>
|
<string>${EXECUTABLE_NAME}</string>
|
||||||
|
@ -89,6 +47,8 @@
|
||||||
<string>1.0</string>
|
<string>1.0</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
|
<key>CFBundleURLTypes</key>
|
||||||
|
<array/>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>1</string>
|
<string>1</string>
|
||||||
<key>LSMinimumSystemVersion</key>
|
<key>LSMinimumSystemVersion</key>
|
||||||
|
@ -99,5 +59,30 @@
|
||||||
<string>MainMenu</string>
|
<string>MainMenu</string>
|
||||||
<key>NSPrincipalClass</key>
|
<key>NSPrincipalClass</key>
|
||||||
<string>NSApplication</string>
|
<string>NSApplication</string>
|
||||||
|
<key>NSServices</key>
|
||||||
|
<array/>
|
||||||
|
<key>UTExportedTypeDeclarations</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>UTTypeConformsTo</key>
|
||||||
|
<array>
|
||||||
|
<string>public.content</string>
|
||||||
|
<string>com.apple.package</string>
|
||||||
|
</array>
|
||||||
|
<key>UTTypeDescription</key>
|
||||||
|
<string>Medianno Database</string>
|
||||||
|
<key>UTTypeIdentifier</key>
|
||||||
|
<string>org.aereperennius.medianno-database</string>
|
||||||
|
<key>UTTypeTagSpecification</key>
|
||||||
|
<dict>
|
||||||
|
<key>public.filename-extension</key>
|
||||||
|
<array>
|
||||||
|
<string>medianno</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
<key>UTImportedTypeDeclarations</key>
|
||||||
|
<array/>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user