以编程方式将新记录添加到Cocoa Core数据实体

时间:2011-02-10 20:52:29

标签: objective-c cocoa macos core-data cocoa-bindings

我在Cocoa中创建一个简单的基于文档的应用程序。此应用程序的每个文档基本上应该管理日期和注释的数组,因此每个记录都是日期和注释(textview)。此外,每个文档都受密码保护。

为此,我创建了一个名为HistoryElement的Core Data实体(包含日期和notes属性),我还创建了一个Settings实体,该实体应该只包含一个包含打开文件密码的记录(我没有找到了一个更好的方法,有一个?密码绑定到每个文件,因此我不能使用首选项,因为它不是全局应用程序密码)。

我有一个首选项标签,其中包含一个密码文本字段,该文本字段绑定到“设置”实体的密码属性。

好的...现在的问题是:当我创建一个新文档时,Settings实体上没有记录,所以我希望以编程方式添加一个,这样用户就可以放(如果它想保护它的文件)密码文本字段中的密码。

相反,如果我打开现有文件,它应该会发现已经添加了“设置”实体的记录,并且不应再次创建它,而是密码文本字段应该使用此文件。

我尝试了很多方法,但我无法做到这一点。我试过这个例子:

if([[settingsArrayController arrangedObjects] count] == 0) {`

    NSLog(@"Init settings");`

    [settingsArrayController add:self];`

} 

在我创建新文档时似乎添加了一条新记录,但是如果我在密码文本字段中输入密码然后保存文档,当我再次打开文档时,[[settingsArrayController arrangedObjects] count]会返回 0 并再次创建新记录......

我该怎么做?有一种更好/简单/优雅的方法来保护带有密码的文件吗?

1 个答案:

答案 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