Adding a new record programmatically to a Cocoa Core Data Entity
i'm making a simple document-based application in Cocoa. Each document of this app should basically manage an array of Dates and Notes, so each record is a date and a note (textview). Also each document is protected by password.
To do that i created a Core Data entity called HistoryElement (that contains a date and a notes attribute), i also created a Settings entity that should have only a record which contains the password to open the file (i didn't found a better method, there is one ? The password is tied to each file, so i can't use preferences because it's not a global application password).
I have a preference tab which contain a Password textfield that binds to the password attribute of the Settings entity.
Ok...the problem is now this: when i create a new document there are no records on the Settings entity, so i wish to programmatically add one, so the user can put (if it want to protect it's file) the password in the password text field.
Instead, if i'm opening an existing file it should find that a record for Settings entity has been already add and it shouldn't create it again, instead the password text field should use this one.
I tried many ways, but i'm unable to do that. I tried for example this:
if([[settingsArrayController arrangedObjects] count] == 0) {`
开发者_开发知识库
NSLog(@"Init settings");`
[settingsArrayController add:self];`
}
It seems that it adds a new record when i create a new document, but if i put a password in the password text field and then save the document, when i open the document again the [[settingsArrayController arrangedObjects] count]
returns 0
and it creates a new record again...
How can i do that ? There is a better/simple/elegant way to protect a document with a password ?
You need to add the code to NSPersistentDocument after the managedObjectContext has been initialized and the data has been loaded. It's hard to say what's wrong with the sample code you posted without knowing where you put it.
One easy place you could put it is in the windowControllerDidLoadNib. For example,
- (void)windowControllerDidLoadNib:(NSWindowController *)windowController
{
[super windowControllerDidLoadNib:windowController];
// user interface preparation code
NSManagedObjectContext *moc = [self managedObjectContext];
NSSet *settings = [moc fetchObjectsForEntityName:@"Settings"
withPredicate:nil];
if ([settings count] == 0)
{
NSManagedObject *obj = [NSEntityDescription insertNewObjectForEntityForName:@"Settings"
inManagedObjectContext:moc];
[obj setValue:@"myPass" forKey:@"password"];
} else {
// password record already exists, do something else.
}
}
Note that I am using a category on NSManagedObjectContext that does all the boiler plate query stuff:
// Convenience method to fetch the array of objects for a given Entity
// name in the context, optionally limiting by a predicate or by a predicate
// made from a format NSString and variable arguments.
//
- (NSSet *)fetchObjectsForEntityName:(NSString *)newEntityName
withPredicate:(id)stringOrPredicate, ...
{
NSEntityDescription *entity = [NSEntityDescription
entityForName:newEntityName inManagedObjectContext:self];
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
[request setEntity:entity];
if (stringOrPredicate)
{
NSPredicate *predicate;
if ([stringOrPredicate isKindOfClass:[NSString class]])
{
va_list variadicArguments;
va_start(variadicArguments, stringOrPredicate);
predicate = [NSPredicate predicateWithFormat:stringOrPredicate
arguments:variadicArguments];
va_end(variadicArguments);
}
else
{
NSAssert2([stringOrPredicate isKindOfClass:[NSPredicate class]],
@"Second parameter passed to %s is of unexpected class %@",
sel_getName(_cmd), [stringOrPredicate className]);
predicate = (NSPredicate *)stringOrPredicate;
}
[request setPredicate:predicate];
}
NSError *error = nil;
NSArray *results = [self executeFetchRequest:request error:&error];
if (error != nil)
{
[NSException raise:NSGenericException format:@"%@",[error description]];
}
return [NSSet setWithArray:results];
}
And that should be all there is to it.
I have created a quick sample project that illustrates what you need to do at: http://dl.dropbox.com/u/21359504/coredata-example.zip
精彩评论