我在Cocoa中创建一个简单的基于文档的应用程序。此应用程序的每个文档基本上应该管理日期和注释的数组,因此每个记录都是日期和注释(textview)。此外,每个文档都受密码保护。
为此,我创建了一个名为HistoryElement的Core Data实体(包含日期和notes属性),我还创建了一个Settings实体,该实体应该只包含一个包含打开文件密码的记录(我没有找到了一个更好的方法,有一个?密码绑定到每个文件,因此我不能使用首选项,因为它不是全局应用程序密码)。
我有一个首选项标签,其中包含一个密码文本字段,该文本字段绑定到“设置”实体的密码属性。
好的...现在的问题是:当我创建一个新文档时,Settings实体上没有记录,所以我希望以编程方式添加一个,这样用户就可以放(如果它想保护它的文件)密码文本字段中的密码。
相反,如果我打开现有文件,它应该会发现已经添加了“设置”实体的记录,并且不应再次创建它,而是密码文本字段应该使用此文件。
我尝试了很多方法,但我无法做到这一点。我试过这个例子:
if([[settingsArrayController arrangedObjects] count] == 0) {`
NSLog(@"Init settings");`
[settingsArrayController add:self];`
}
在我创建新文档时似乎添加了一条新记录,但是如果我在密码文本字段中输入密码然后保存文档,当我再次打开文档时,[[settingsArrayController arrangedObjects] count]
会返回 0
并再次创建新记录......
我该怎么做?有一种更好/简单/优雅的方法来保护带有密码的文件吗?
答案 0 :(得分:5)
在初始化managedObjectContext并加载数据后,您需要将代码添加到NSPersistentDocument。很难说你发布的示例代码有什么问题而不知道你把它放在哪里。
一个容易放置的地方是windowControllerDidLoadNib。例如,
- (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.
}
}
请注意,我在NSManagedObjectContext上使用了一个类别来执行所有样板查询:
// 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];
}
这应该是它的全部内容。
我创建了一个快速示例项目,说明了您需要执行的操作:http://dl.dropbox.com/u/21359504/coredata-example.zip