PDA

View Full Version : Core Data - creating an instance of an entity




zedLondon
Jul 11, 2007, 09:11 AM
Hey guys. My first time playing with Core data. I've hit a little snag and after reading the docs and tutorials I could find. I'm still stumped.

The problem is that I need to create an instance of an entity whenever an instance of another entity is created.

I have a 'Language' entity which has a relationship to a 'Generator' Entity. The relationship is one to one. The generator uses a custom class that inherits from NSManagedObject (it needs to do some other stuff besides manage data)

In the nib file I have an NSArrayController for the Language entities and an NSController object for the Generator. The NSController gets it's content from a selection binding to the Language NSArrayController.

Now when I create a new language in the NSArrayController I need it to create a new instance of the generator to accompany it.

So i created a custom class for the Language Entity and implemented init like this


-(id)init
{
if(self = [super init])
{
newGenerator = [[Generator alloc] init];
[self setobject:newGenerator forKey:@"generator"];
}
}


But that doesn't seem to do the trick. When i add a new Language I don't seem to get a new Generator. (i've got other interface elements that access attributes of the generator and i can't add items to them, even though they are connected properly)



kainjow
Jul 11, 2007, 09:47 AM
NSManagedObjects are initialized via initWithEntity:insertIntoManagedObjectContext: - try that instead of just init

whooleytoo
Jul 11, 2007, 09:51 AM
I'm not at all familiar with Core Data; so I don't know if there's an easier/better way to do what you're doing... but..

Are you sure the init method that NSArrayController is calling is the same one that you've posted above?

Also, the "setobject:forKey:" method, you call it below with a lowercase "O", was that a typo?

zedLondon
Jul 11, 2007, 10:14 AM
NSManagedObjects are initialized via initWithEntity:insertIntoManagedObjectContext: - try that instead of just init

Cool I'll give that a shot.

How do i reference the managed object context of the app?

So the generator init should read

newGenerator = [[Generator alloc] initWithEnity:Generator insertIntoManagedObjectContext:xxxxx?]

zedLondon
Jul 11, 2007, 10:16 AM
I'm not at all familiar with Core Data; so I don't know if there's an easier/better way to do what you're doing... but..

Are you sure the init method that NSArrayController is calling is the same one that you've posted above?

Also, the "setobject:forKey:" method, you call it below with a lowercase "O", was that a typo?

I'm not sure anymore. I thought it was. But that might be wrong.

And yeh I had setObject :)

whooleytoo
Jul 11, 2007, 10:21 AM
I was going to suggest you should override the initWithEntity... method (but the documentation suggests you shouldn't) instead of overriding init, it would work.

You could put the code to create the generator in one of the awake... methods, which should work regardless of which init.. method is used.

zedLondon
Jul 11, 2007, 10:32 AM
Thanks for the steer guys

I'll have another fiddle when i get home and let you know how i get on.

kainjow
Jul 11, 2007, 10:54 AM
How do i reference the managed object context of the app?

Just how you'd reference any other object in your application. When you create a "Core Data Application" project in Xcode, Apple provides within the project code for creating the managed object context and other Core Data objects. Check it out to see how they do it.

Eraserhead
Jul 11, 2007, 05:44 PM
NSManagedObjectContext *context=[[[NSDocumentController sharedDocumentController] currentDocument] managedObjectContext];

is how you get the context in a document based app, it's on the Core Data page on Apples site for a non-document based one.

zedLondon
Jul 11, 2007, 07:02 PM
Thanks loads guys.

After re-reading the docs and helped by what you guys wrote here I put this in my LanguageMO class and it seems to have done the trick


- (void) awakeFromInsert
{

[super awakeFromInsert];

// define context and model for current document
NSManagedObjectModel *model =[[[NSDocumentController sharedDocumentController] currentDocument] managedObjectModel];
NSManagedObjectContext *context = [[[NSDocumentController sharedDocumentController] currentDocument] managedObjectContext];

NSEntityDescription *generatorEntity = [[model entitiesByName] objectForKey:@"Generator"];

GeneratorMO *newGenerator = [[GeneratorMO alloc] initWithEntity:generatorEntity
insertIntoManagedObjectContext:context];

[self setValue:newGenerator forKey:@"generator"];

}

Once again, thanks loads guys

Eraserhead
Jul 12, 2007, 03:35 AM
PS, Why are you subclassing NSManagedObject, there really is little point, I have personally found no need to.

zedLondon
Jul 12, 2007, 07:37 AM
PS, Why are you subclassing NSManagedObject, there really is little point, I have personally found no need to.

The generator entity in addition to storing data also needs to have a number of methods to process that data and produce new data from it. I could have had another class do this and just use the generator as a data store, but that seemed really ugly, especially as the methods were so intrinsically linked to the data stored in generator.

The generator stores

- an array of sylable shapes and the frequency of their occurance
- an array of letter categories
- the minimum number of sylables in a word
- the max number of sylables in a word
- the average number of sylables in a word
- the number of words to generate

It then has the following methods.
-generate an array of random words based on the above information
-an inverse normal distribution to work out the required number of sylables in a word.

Eraserhead
Jul 12, 2007, 07:42 AM
The generator entity in addition to storing data also needs to have a number of methods to process that data and produce new data from it. I could have had another class do this and just use the generator as a data store, but that seemed really ugly, especially as the methods were so intrinsically linked to the data stored in generator.

The generator stores
- an array of sylable shapes and the frequency of their occurance
- an array of letter categories
- the minimum number of sylables in a word
- the max number of sylables in a word
- the average number of sylables in a word
- the number of words to generate

It then has the following methods.
-generate an array of random words based on the above information
-an inverse normal distribution to work out the required number of sylables in a word.

Some of these might be better stored in the model itself, it's worth considering as it'd make saving the information quicker.

zedLondon
Jul 12, 2007, 07:56 AM
Some of these might be better stored in the model itself, it's worth considering as it'd make saving the information quicker.


All the data elements are stored in the model. The generator entity just uses a subclass of NSManagedObject that provides the inverse normal and generate methods.

I don't provide any accessor methods or storage variables for any of the data elements. I just use the [self valueForKey:@"xxx"] approach.

whooleytoo
Jul 12, 2007, 01:26 PM
All the data elements are stored in the model. The generator entity just uses a subclass of NSManagedObject that provides the inverse normal and generate methods.

I don't provide any accessor methods or storage variables for any of the data elements. I just use the [self valueForKey:@"xxx"] approach.

Using valueForKey: and setValue:forKey: can be a good idea, since they'll first try to use accessors if present, then set the instance variables directly if not (autoreleasing the old value and retaining the new).

So, if you do decide to add accessors later, you don't need to change any code to call them (provided you use the appropriate method naming conventions).