【问题标题】:Adding a new record programmatically to a Cocoa Core Data Entity以编程方式将新记录添加到 Cocoa 核心数据实体
【发布时间】:2011-02-10 20:52:29
【问题描述】:

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

为此,我创建了一个名为 HistoryElement 的核心数据实体(包含日期和注释属性),我还创建了一个设置实体,它应该只有一条记录,其中包含打开文件的密码(我没有找到更好的方法,有吗?密码与每个文件绑定,所以我不能使用首选项,因为它不是全局应用程序密码)。

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

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

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

我尝试了很多方法,但我无法做到。例如,我试过这样:

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

    NSLog(@"Init settings");`

    [settingsArrayController add:self];`

} 

它似乎在我创建新文档时添加了一条新记录,但是如果我在密码文本字段中输入密码然后保存文档,当我再次打开文档时[[settingsArrayController arrangedObjects] count] 返回 @ 987654323@ 又创造了一个新纪录……

我该怎么做?有更好/简单/优雅的方法来使用密码保护文档吗?

【问题讨论】:

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


    【解决方案1】:

    在 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

    【讨论】:

      最近更新 更多