Core Data and Document Packages
-
Aloha,
I'm taking the plunge and switching a fair chunk of code to using
Core Data instead of my own management of an SQLite database. At
least that's the current plan. ;)
My document-based app has a document type which uses a package
instead of just a single file to store data in, because there is a
need to store related files inside the package as well. Currently I'm
doing some relatively simple overloading of standard NSDocument
methods to open and save the database by using a path based off of
the -fileName.
With NSPersistentDocument, by default it uses the document's -
fileName as the path for the persistent store. What is the best way
to retarget it so that it uses a different path within the package? I
imagine someone here must have done it, so I'm hoping to not have to
fiddle for so long to figure it out, however it seems that I might
simply be able to override
configurePersistentStoreCoordinatorForURL:ofType:error: and pass a
different URL to super's implementation? Will there be any side
effects to this?
Thanks. Total Core Data newb,
--
Seth Willits -
On Jul 3, 2007, at 1:38 AM, Seth Willits wrote:
> With NSPersistentDocument, by default it uses the document's -
> fileName as the path for the persistent store. What is the best way
> to retarget it so that it uses a different path within the package?
> I imagine someone here must have done it, so I'm hoping to not have
> to fiddle for so long to figure it out, however it seems that I
> might simply be able to override
> configurePersistentStoreCoordinatorForURL:ofType:error: and pass a
> different URL to super's implementation? Will there be any side
> effects to this?
<http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/Cla
sses/NSPersistentDocument_Class/Reference/Reference.html>
mmalc -
On Jul 3, 2007, at 5:57 AM, mmalc Crawford wrote:
>> With NSPersistentDocument, by default it uses the document's -> ApplicationKit/Classes/NSPersistentDocument_Class/Reference/
>> fileName as the path for the persistent store. What is the best
>> way to retarget it so that it uses a different path within the
>> package? I imagine someone here must have done it, so I'm hoping
>> to not have to fiddle for so long to figure it out, however it
>> seems that I might simply be able to override
>> configurePersistentStoreCoordinatorForURL:ofType:error: and pass a
>> different URL to super's implementation? Will there be any side
>> effects to this?
>
> <http://developer.apple.com/documentation/Cocoa/Reference/
> Reference.html>
>
> mmalc
I'm not sure how that was supposed to be helpful given that I had
already read the documentation (not to mention the tutorials, sample
code, Google, and the list archives) and came here asking for further
help.
As it turns out, overriding readFromURL:/writeToURL: and
configurePersistentStoreCoordinatorForURL: is working dandily so far.
In my previous experience doing this without Core Data, I had ran
into some trouble with getting this to work, but the circumstances
are different so it's a bit simpler and more direct than I was
expecting it to be.
For posterity, incomplete but demonstrable code of how to do it:
- (BOOL)configurePersistentStoreCoordinatorForURL:(NSURL *)url ofType:
(NSString *)fileType error:(NSError **)error;
{
NSString * storePath = [[url relativePath]
stringByAppendingPathComponent:@"Data.sqldb"];
return [super configurePersistentStoreCoordinatorForURL:[NSURL
fileURLWithPath:storePath] ofType:fileType error:error];
}
- (BOOL)readFromURL:(NSURL *)absoluteURL ofType:(NSString *)typeName
error:(NSError **)error;
{
NSString * packagePath = [absoluteURL relativePath];
BOOL isDirectory = NO;
if (![[NSFileManager defaultManager]
fileExistsAtPath:packagePath isDirectory:&isDirectory] || !
isDirectory) {
// create an error
return NO;
}
return [super readFromURL:absoluteURL ofType:typeName error:error];
}
- (BOOL)writeToURL:(NSURL *)absoluteURL ofType:(NSString *)typeName
forSaveOperation:(NSSaveOperationType)saveOperation
originalContentsURL:(NSURL *)absoluteOriginalContentsURL error:
(NSError **)error;
{
NSString * packagePath = [absoluteURL relativePath];
BOOL isDirectory = NO;
if (![[NSFileManager defaultManager]
createDirectoryAtPath:packagePath attributes:nil]) {
// create an error
return NO;
}
return [super writeToURL:absoluteURL ofType:typeName
forSaveOperation:saveOperation
originalContentsURL:absoluteOriginalContentsURL error:error];
}
--
Seth Willits -
>> On Jul 3, 2007, at 5:57 AM, mmalc Crawford wrote:>>> >
>>>
>>> <http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/Cla
sses/NSPersistentDocument_Class/Reference/Reference.html
>>>
>>
>> I'm not sure how that was supposed to be helpful given that I had
>> already read the documentation (not to mention the tutorials,
>> sample code, Google, and the list archives) and came here asking
>> for further help.
You clearly didn't read closely enough - the reference states (and I
think it's mentioned elsewhere) that NSPersistentDocument doesn't
support file wrappers...
>> As it turns out, overriding readFromURL:/writeToURL: and
>> configurePersistentStoreCoordinatorForURL: is working dandily so far.
It will almost certainly fail at some point -- probably during a revert.
mmalc -
On Jul 3, 2007, at 1:38 AM, Seth Willits wrote:
> My document-based app has a document type which uses a package
> instead of just a single file to store data in, because there is a
> need to store related files inside the package as well. Currently
> I'm doing some relatively simple overloading of standard NSDocument
> methods to open and save the database by using a path based off of
> the -fileName.
One major problem with using file wrappers is ensuring atomic
saves. If one of your save operations needs to update SQLite and add/
remove/update other files in the file wrapper, the only real option
would be to make a copy of the entire wrapper, apply the changes
(including the SQLite transaction) to the copy and then atomic swap
the two wrapper directories using FSExchangeObjects or the like. At
this point, you've lost most of the benefit of putting it in a SQLite
database (at least in terms of save speed; there are obviously other
benefits).
What I wouldn't give for a transactional filesystem with copy-on-
write...
-tim -
On Jul 3, 2007, at 1:42 PM, Seth Willits wrote:
> As it turns out, overriding readFromURL:/writeToURL: and
> configurePersistentStoreCoordinatorForURL: is working dandily so
> far...
... until you try to save the second time. :)
I continued to fiddle with readFromURL/writeToURL and tried to get it
to work (I added the store myself from
configurePersistentStoreCoordinatorForURL), but no matter what I did,
I always end up with crash when doing a second save caused by super's
implementation of writeToURL: returning NO but not setting the
outError causing a crash when it tries to display the error. Nothing
in the log, and NSZombie didn't catch anything either. Wonderful!
So I'm back at square 1 basically.
I'm currently fiddling with an NSDocument subclass, but I'm sure I'll
hit a wall eventually...
--
Seth Willits -
On Jul 3, 2007, at 3:38 AM, Seth Willits wrote:
> I'm taking the plunge and switching a fair chunk of code to using
> Core Data instead of my own management of an SQLite database. At
> least that's the current plan. ;)
>
> My document-based app has a document type which uses a package
> instead of just a single file to store data in, because there is a
> need to store related files inside the package as well. Currently
> I'm doing some relatively simple overloading of standard NSDocument
> methods to open and save the database by using a path based off of
> the -fileName.
>
> With NSPersistentDocument, by default it uses the document's -
> fileName as the path for the persistent store. What is the best way
> to retarget it so that it uses a different path within the package?
> I imagine someone here must have done it, so I'm hoping to not have
> to fiddle for so long to figure it out, however it seems that I
> might simply be able to override
> configurePersistentStoreCoordinatorForURL:ofType:error: and pass a
> different URL to super's implementation? Will there be any side
> effects to this?
Seth,
I've thought about having files associated with my Core Data database
as well and I came up with a different solution that may work for you
as well. Instead of trying to keep the files with the database, you
could designate a folder as a repository for the files. This can even
be a user-preference to relocate this folder. This way you avoid all
the stress of trying to roll them into the database.
The other option, if the files are small enough, is to actually store
them in a Binary Data field of a database table.
Peace,
Kevin Hoctor
<kevin...>
No Thirst Software LLC
http://nothirst.com



