Core Data - creating an instance of an entity

Discussion in 'Mac Programming' started by zedLondon, Jul 11, 2007.

  1. macrumors member

    #1
    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

    Code:
    -(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)
     
  2. Moderator emeritus

    kainjow

    #2
    NSManagedObjects are initialized via initWithEntity:insertIntoManagedObjectContext: - try that instead of just init
     
  3. macrumors 603

    whooleytoo

    #3
    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?
     
  4. macrumors member

    #4
    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?]
     
  5. macrumors member

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

    And yeh I had setObject :)
     
  6. macrumors 603

    whooleytoo

    #6
    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.
     
  7. macrumors member

    #7
    Thanks for the steer guys

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

    kainjow

    #8
    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.
     
  9. macrumors G4

    Eraserhead

    #9
    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.
     
  10. macrumors member

    #10
    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

    Code:
    - (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
     
  11. macrumors G4

    Eraserhead

    #11
    PS, Why are you subclassing NSManagedObject, there really is little point, I have personally found no need to.
     
  12. macrumors member

    #12
    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.
     
  13. macrumors G4

    Eraserhead

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

    #14

    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:mad:"xxx"] approach.
     
  15. macrumors 603

    whooleytoo

    #15
    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).
     

Share This Page