在实体上设置属性并使用“一对多”关系检索它

时间:2009-10-17 16:57:11

标签: iphone objective-c core-data entity attributes

我已经阅读了Apple开发人员指南和教程,并且我浏览了2本关于Core Data主题的iPhone书籍。

我习惯于处理事物的“价值对象”/“实体”方面,然后将它们发送到网络服务或类似服务。但在iPhone上,我自己处理所有事情......残酷的世界:)

来自Apple Developer网站的LocationsTaggedLocationsPhotoLocations示例并未以我可以“计算”的方式向我提供答案。我希望有人能够启发我。

我使用datamodel GUI设置了我的模型。两个实体PersonDreamPerson具有personName字符串属性和一对多dreams关系。 Dreams具有description字符串属性和一对一person关系。

我一直在设置一个简单的tableView应用。 第一个视图是人员列表,第二个视图是他们的梦想列表。

这是我将人添加到modelObjectContext

的方法
Person *newPerson = (Person *)[NSEntityDescription
    insertNewObjectForEntityForName:@"Person" 
    inManagedObjectContext:managedObjectContext];
[newPerson setPersonName:@"Ben Hur"];

好的,然后我在上下文中添加了一个新的梦想:

Dream *newDream = (Dream *)[NSEntityDescription
    insertNewObjectForEntityForName:@"Dream"
    inManagedObjectContext:managedObjectContext];
[newDream setDescription:@"I had a nightmare"];

我现在将梦想添加到这样的人:

[newPerson addDreamObject:newDream];

这对我来说有点模糊,因为xcode在Person类上为我生成了不同的方法/访问器:

@class Dream;

@interface Person :  NSManagedObject  
{
}

@property (nonatomic, retain) NSString * personName;
@property (nonatomic, retain) NSSet* dream;

@end


@interface Person (CoreDataGeneratedAccessors)
- (void)addDreamObject:(Dream *)value;
- (void)removeDreamObject:(Dream *)value;
- (void)addDream:(NSSet *)value;
- (void)removeDream:(NSSet *)value;

@end

在其他情况下,我无需处理实际的保存,检索和数据。我会构建一个名为person的实体/值对象,并给它一个Array来存储梦想。但是这不是核心数据中可能的属性类型,而不是这样做的方式,我已经读过了(在这里也是类似的线程)。

那么样板代码如何工作? 我应该使用addDream并发送一个充满梦想的NSSet吗?或者我可以只信任核心数据来实例化这个并且专门使用addDreamObject发送Person类型的Dreams实体对象吗?

我还使用xcode的样板代码保存上下文。 现在我希望用这个人更新观点,更确切地说是他的名字。

cellForRowAtIndexPath方法中我给出了这个:

NSManagedObject *managedObject = [fetchedResultsController objectAtIndexPath:indexPath];
cell.textLabel.text = [[managedObject valueForKey:@"personName"] description];

一切都很顺利,名字也显示在名单上。

我设置DreamViewControllerPerson对象作为参数。

Person *selectedObject = [[self fetchedResultsController] objectAtIndexPath:indexPath];
dreamView.selectedPerson = selectedObject;

然后我将viewController推到堆栈上,然后输入DreamView。在这里,我似乎无法了解与我“发送”的观点有关的梦想。

这就是我在DreamViewController的{​​{1}}方法中尝试的方法(viewDidLoad是我用来传递selectedPerson对象的访问器):

Person

我似乎无法掌握这一点,而且我目前使用Objective C的经验不允许我从Apple的文档中获取“最佳实践”本质。

1 个答案:

答案 0 :(得分:3)

首先,您需要纠正自己在模型中犯下的错误。你的梦想实体中不能有一个名为“描述”的属性:这是禁止的,因为“描述”它是方法的名称。

从Apple文档(核心数据编程指南):

请注意,属性名称不能与NSObject或NSManagedObject的任何无参数方法名称相同,例如,您不能为属性指定名称“description”(请参阅​​NSPropertyDescription)。

addDreamObject:和addDream:之间的区别在于前者用于在to-many关系中插入Dream对象,而后者用于插入或替换to-many关系的上下文。

你不应该使用

cell.textLabel.text = [[managedObject valueForKey:@"personName"] description];

你应该简单地使用

cell.textLabel.text = [managedObject valueForKey:@"personName"];

关于与您的人相关的梦想,您不需要额外的获取请求。一旦掌握了人物对象,您就可以按如下方式访问该人的梦想:

for(Dream *dream in person.dreams){
   // process your Dream object
}

最后,不清楚为什么不将托管对象上下文显式传递给DreamViewController作为实例变量。这是常见的做法,也在Apple示例代码中显示。另一个错误是检查

if (fetchedObjects == nil)

因为如果查询实际上没有找到任何对象,则返回nil是合法的;你必须检查你的NSError对象是否不是nil(你必须在执行你的获取请求之前将它初始化为nil):

if(error)

声明

NSLog(@"The Dream object says: %@", [d description]);

甚至可能会使您的应用程序崩溃,正如我在回答的开头所解释的那样。