在实体上设置属性并通过“一对多”检索它。关系
我已经阅读了 Apple 开发者指南和教程,还阅读了 2 本 iPhone 书籍,其中涉及核心数据的主题。
我习惯于处理事物的“值对象”/“实体”方面,然后将它们发送到网络服务等。但在 iPhone 上,我可以自己处理所有事情……残酷的世界:)
Apple 开发者网站上的 Locations
、TaggedLocations
和 PhotoLocations
示例并不以我可以“计算”的方式给我答案。我希望这里有人能启发我。
我已经使用数据模型 GUI 设置了模型。两个实体,人
和梦
。 Person
具有 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
发送 Dreams
类型的 Person
实体对象吗?
我还使用 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
的 viewDidLoad
方法中尝试的方法(selectedPerson
是我用来传递 Person< /code> object):
- (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 文档的字里行间抓住“最佳实践”的本质。
I have been through the Apple Developer guides and tutorials and I been through 2 iPhone books brushing on the subject of Core Data.
I am used to handling the "value object"/"entity" side of things and then send them of to a web service or the likes. But on the iPhone I get to handle everything myself… cruel world :)
The Locations
, TaggedLocations
and PhotoLocations
examples from the Apple Developer site do not give me the answers in a way I can "compute". I hope someone here can enlighten me.
I have set up my model using the datamodel GUI. two entities, Person
and Dream
.Person
has a personName
string attribute and a one-to-many dreams
relationship.Dreams
has a description
string attribute and a one-to-one person
relationship.
I have been setting up a simple tableView
app.
First view is a list of persons and the second view is a list of their dreams.
This is how I add a person to the modelObjectContext
:
Person *newPerson = (Person *)[NSEntityDescription
insertNewObjectForEntityForName:@"Person"
inManagedObjectContext:managedObjectContext];
[newPerson setPersonName:@"Ben Hur"];
OK, I then add a new dream to the context:
Dream *newDream = (Dream *)[NSEntityDescription
insertNewObjectForEntityForName:@"Dream"
inManagedObjectContext:managedObjectContext];
[newDream setDescription:@"I had a nightmare"];
I now add the dream to the person like this:
[newPerson addDreamObject:newDream];
Here it gets a bit hazy to me, because xcode generated different methods/accessors for me on the Person
Class:
@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
In other situations, where I did not have to handle the actual saving, retrieving, data. I would have build an entity/value object called person
and given it an Array
to store the dreams. But this is not a possible attribute type in core data, and not the way to do it, I have read (in here in similar threads too).
So how does this boilerplate code work?
Am I supposed to use the addDream
and send it an NSSet
filled with dreams? or can I just trust core data to instantiate this and exclusively use the addDreamObject
send the Person
entity objects of type Dreams
?
I also save the context using the boilerplate code from xcode.
Now I wish to update the view with this person, more precisely his name.
In the cellForRowAtIndexPath
method I give it this:
NSManagedObject *managedObject = [fetchedResultsController objectAtIndexPath:indexPath];
cell.textLabel.text = [[managedObject valueForKey:@"personName"] description];
Again all is well and the name is displayed on the list.
I set up my DreamViewController
to take a Person
object as a parameter.
Person *selectedObject = [[self fetchedResultsController] objectAtIndexPath:indexPath];
dreamView.selectedPerson = selectedObject;
Then I push the viewController
onto the stack and we enter the DreamView
. Here I can not seem to get at the at the dreams related to the person I "sent along" with the view.
This is what I'm trying in the DreamViewController
's viewDidLoad
method (selectedPerson
is the accessor I use to pass the Person
object):
- (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];
}
I really can't seem to get the hang of this and my current experience with Objective C does not allow me to just grab the "best practice" essence from between the lines of Apple's documentation.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
首先,您需要纠正模型中犯的错误。你的梦想实体中不能有一个名为“描述”的属性:这是禁止的,因为“描述”是方法的名称。
来自 Apple 文档(核心数据编程指南):
请注意,属性名称不能与 NSObject 或 NSManagedObject 的任何无参数方法名称相同,例如,您不能为属性指定名称“description”(请参阅 NSPropertyDescription)。
addDreamObject: 和 addDream: 之间的区别在于,前者用于在多对多关系中插入 Dream 对象,而后者用于一次性插入或替换对多关系的上下文。
您不应该使用
您应该简单地使用
关于与您的人相关的梦想,您不需要额外的获取请求。一旦您拥有了 person 对象,您只需按如下方式访问该人的梦想:
最后,不清楚为什么您不将托管对象上下文作为实例变量显式传递给 DreamViewController。这是常见的做法,Apple 示例代码中也显示了这一点。另一个错误是检查,
因为如果查询实际上没有找到对象,则返回 nil 是合法的;相反,您必须检查您的 NSError 对象是否不为零(您必须在执行获取请求之前将其初始化为 nil):
该语句
甚至可能使您的应用程序崩溃,正如我的答案开头所解释的那样。
You need to correct a mistake you made in your model, to begin with. You can NOT have an attribute called "description" in your dreams entity: this is forbidden because "description" it's the name of a method.
From the Apple documentation (Core Data programming guide):
Note that a property name cannot be the same as any no-parameter method name of NSObject or NSManagedObject, for example, you cannot give a property the name “description” (see NSPropertyDescription).
The difference between addDreamObject: and addDream: is that the former is used to insert a Dream object in the to-many relationship, while the latter is used to insert or replace one-shot the contexts of the to-many relationship.
You should not use
you should use simply
Regarding the dreams related to your person, you do not need an additional fetch request. Once you have your person object, you simply access that person's dreams as follows:
Finally, it is not clear why you do not pass explicitly the managed object context to your DreamViewController as an instance variable. This is common practice, also shown in Apple sample codes. Another error is checking for
because it is legal to return nil if the query actually found no objects; you must instead check if your NSError object is not nil (you must initialize it to nil BEFORE executing your fetch request):
The statement
may even crash your application, as explained at the beginning of my answer.