1

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

我习惯于处理事物的“值对象”/“实体”方面,然后将它们发送到 Web 服务等。但在 iPhone 上,我可以自己处理所有事情……残酷的世界 :)

LocationsApple Developer 网站上的TaggedLocationsPhotoLocations示例并没有以我可以“计算”的方式给我答案。我希望这里有人可以启发我。

我已经使用数据模型 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 在PersonClass 上为我生成了不同的方法/访问器:

@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];

一切都很好,名称显示在列表中。

我将我的设置DreamViewController为将Person对象作为参数。

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

然后我将 压入viewController堆栈,然后我们进入DreamView. 在这里,我似乎无法理解与我“送来”的人有关的梦境。

这是我在DreamViewController'sviewDidLoad方法中尝试的(selectedPerson是我用来传递Person对象的访问器):

- (void)viewDidLoad {
[super viewDidLoad];
self.title = @"One Person";

NSManagedObjectContext *context = selectedPerson.managedObjectContext;

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Dream"
                                          inManagedObjectContext:context];
[fetchRequest setEntity:entity];

NSError *error;
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
if (fetchedObjects == nil) {
    // Handle the error.
    NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    exit(-1);  // Fail
}

NSMutableArray *mutableArray = [fetchedObjects mutableCopy];
self.dreamArray = mutableArray;
NSLog(@"the length of dreamArray: %i",[self.dreamArray count] );

Dream *d = [dreamArray objectAtIndex:0];
NSLog(@"The Dream object says: %@", [d description]);
[mutableArray release];

[fetchRequest release];
}

我似乎真的无法掌握这一点,而且我目前使用 Objective C 的经验不允许我从 Apple 文档的字里行间中抓住“最佳实践”的精髓。

4

1 回答 1

3

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

来自 Apple 文档(Core Data 编程指南):

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

addDreamObject: 和 addDream: 的区别在于前者用于在一对多关系中插入 Dream 对象,而后者用于在一对多关系中插入或替换 one-shot 的上下文。

你不应该使用

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

你应该简单地使用

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

关于与您的人相关的梦想,您不需要额外的获取请求。一旦你有了你的 person 对象,你只需按如下方式访问那个人的梦想:

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

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

if (fetchedObjects == nil)

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

if(error)

该声明

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

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

于 2009-10-18T08:29:15.587 回答