views:

443

answers:

2

Hi Folks,

I´ve some trouble with implementing Core Data to my existing iPhone-Project. First I wanna give you a more detailed view on it:

  • Some of my classes are nested into each other: The class "Game" has an NSArray with objects of class "Player", the class "Player" has an NSArray with objects of class "Item" in turn.

  • What I wanna do is saving an instance of my "uppest" class "Game" (e.g. when leaving my app).

I tried out some tutorials about Core Data, but there are still some questions:

  1. Do I have to create an entity for each of my classes or just for "Game"?
  2. If I have to do it for each one: I think I will have to create ALL relationships between my classes, but: How to create the relationships e.g. between "Game" an "Player" (please remind: I hold MANY players in ONE NSArray)..
  3. What about changing my existing project? What I allready did is copying the missing methods into my AppDelegate. But what will I have to do with my classes, especially with Getter/Setter-methods? Just change "@synthesize" to "@dynamic" in the implementation?

I hope for some light in my dark ;)

Thanks a lot right now

Mac1988

+1  A: 

What I recommend is to setup your database model in xcode, then when you have done that... choose the entitys and choose from the menu File > New File. Then choose the "Managed Object Class" from the "Cocoa touch class". After "Next" choose where to save the files, and at the next step XCode will ask you which entitys should be generated to files.

After you have done that, you can implemend the functions you need into your e.g. you delegate. My rekommendation is to leave your existing stuff as it is and use the core data classes as their own. Just pull the data you need from you existing classes/arrays and put them in to the database as you need them. When retrieving, the otherway around... get them from the DB and add them to your functions / classes.

Example from one of my projects:

The .h file

@class quicklistSet;

@interface rankedAppDelegate : NSObject <UIApplicationDelegate, UITabBarControllerDelegate> {
[...]

    NSMutableArray *_searchHistory;
    NSMutableArray *_quickList;
}

[...]

@property (nonatomic, retain) NSMutableArray *_searchHistory;
@property (nonatomic, retain) NSMutableArray *_quickList;

/* Quicklist functions */
- (void)addToQuicklist:(quicklistSet *)theQuicklistSet;
- (BOOL)checkIfQuicklistExists:(quicklistSet*)theQuicklistSet;
- (NSMutableArray *)getQuicklists;
- (void)deleteQuicklist:(NSNumber*)theAppId;


@end

The .m file

#import "quicklistSet.h"
#import "quicklist.h"

@implementation rankedAppDelegate

@synthesize window;
@synthesize tabBarController;
@synthesize _searchHistory, _quickList;

[...]

/* Quicklist functions */
- (void)addToQuicklist:(quicklistSet *)theQuicklistSet
{
    BOOL exists = [self checkIfQuicklistExists:theQuicklistSet];

    if(!exists)
    {
     quicklist *theQuicklist = (quicklist *)[NSEntityDescription insertNewObjectForEntityForName:@"quicklist"
                          inManagedObjectContext:self.managedObjectContext];

     [theQuicklist setAppName:[theQuicklistSet _appName]];
     [theQuicklist setAppId:[theQuicklistSet _appId]];
     [theQuicklist setAppImage:[theQuicklistSet _appImage]];
     [theQuicklist setCountryId:[theQuicklistSet _countryId]];
     [theQuicklist setCategoryId:[theQuicklistSet _categoryId]];
     [theQuicklist setLastCheck:[theQuicklistSet _lastCheck]];
     [theQuicklist setLastRank:[theQuicklistSet _lastRank]];

     [_quickList addObject:theQuicklist];

     [self saveAction];
    }
    else {
     NSLog(@"Existing quicklistSet: %@", [theQuicklistSet _appName]);
    }
}

- (BOOL)checkIfQuicklistExists:(quicklistSet*)theQuicklistSet
{
    // Get the categories
    NSMutableArray *quicklistArray = [self getQuicklists];

    BOOL exists = NO;

    for(quicklist *dbQuicklist in quicklistArray)
    {
     if([[dbQuicklist appId] isEqualToNumber:[theQuicklistSet _appId]])
     {
      exists = YES;
      continue;
     }
    }

    return exists;
}

- (NSMutableArray *)getQuicklists
{
    if(_quickList == NULL)
    {
     NSLog(@"Array is null");

     NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];

     NSEntityDescription *entity = [NSEntityDescription entityForName:@"quicklist" 
                 inManagedObjectContext:self.managedObjectContext];
     [fetchRequest setEntity:entity];

     NSError *error;
     NSArray *items = [[self.managedObjectContext
            executeFetchRequest:fetchRequest error:&error] retain];

     NSMutableArray *returnArray = [[[NSMutableArray alloc] initWithArray:items] retain];

     _quickList = returnArray;

     [fetchRequest release];
    }
    else {
     NSLog(@"Not null. Count: %d", [_quickList count]);
    }

    return _quickList;
}

- (void)deleteQuicklist:(NSNumber*)theAppId
{
    NSLog(@"Delete row");

    // Create a new managed object context for the new book -- set its persistent store coordinator to the same as that from the fetched results controller's context.
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"quicklist" 
                inManagedObjectContext:self.managedObjectContext];

    [fetchRequest setEntity:entity];
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"appId=%@",theAppId];
    [fetchRequest setPredicate:predicate];

    NSError *error;
    NSArray *items = [self.managedObjectContext
          executeFetchRequest:fetchRequest error:&error];
    [fetchRequest release];

    if([items count] > 0)
    {
     NSManagedObject *eventToDelete = [items objectAtIndex:0];
     [self.managedObjectContext deleteObject:eventToDelete];

     [self saveAction];
    }
}
/* END Quciklist functions */

[...]

@end

EDIT: The quicklistSet was my existsing class, the quicklist is my coredata class.

I hope this helped.

Regards, Paul Peelen

Paul Peelen
Hi Paul, thank you for your answer and your example. What you mean is create a new class "GameData" which is handled by Core Data, and pull and save my objects "from there", right? What I still didn´t understand at all is how to create the entity: e.g. one attribute "Player" and a to-many-relationship to my existing "Player"-class? Or will I have to create a new "Player"-class, too? Or is it all terrible wrong? ;)
Mac1988
I understand what you mean, but I can't give you an straight answer on that. I am too unexperienced with core-data yet. What I do know is that from each entity core data creates a class with dynamic values in it. You can also set relations to each-other, but then you just add another class to the entity.I think you will have to create a new player class as well, but maybe someone with more experience could answer your question better.Good luck!
Paul Peelen
+1  A: 
  1. Yes, you want to create an entity for all of the classes you mentioned.

  2. You've already got the answer to this in your question: make a one-to-many relationship. For example, for the players relationship of Game, click the "To-many relationship" checkbox in the data model editor.

  3. You'll want to have your data classes (Game, Player, Item) inherit from NSManagedObject. You'll probably want to remove all of the instance variables that correspond to the attributes you added in Core Data. For the to-many relationships (players, items), you'll definitely want to get rid of the NSArray member variable you were using. Instead, do like you were saying and create @dynamic accessors for the players and items properties. Note that you want to use an NSSet instead of an NSArray for players and items.

For example, the header for your Game class might look like this:

@interface Game : NSManagedObject {

}

@property(nonatomic, retain) NSSet *players
@property(nonatomic, retain) NSString *someOtherProperty;
@property(nonatomic, retain) NSNumber *yetAnotherProperty;

@end

And then your implementation file might look like:

#import "Game.h"

@implementation Game

@dynamic players, someOtherProperty, yetAnotherProperty;

- (void)awakeFromInsert {
    // do initialization here
}

// other methods go here

@end

Also, be careful when modifying the players and items properties. The Using Managed Objects section of the Core Data Programming guide has a lot of good details, but basically to add a Player to a Game instance, you would do

[game addPlayerObject:newPlayer];

To actually create the new player, you would do something like:

NSManagedObject *newPlayer = [NSEntityDescription insertNewObjectForEntityForName:@"Player" inManagedObjectContext:context];
Jacques