I am loading my app with a property list of data from a web site. This property list file contains an NSArray of NSDictionaries which itself contains an NSArray of NSDictionaries. Basically, I'm trying to load a tableView of restaurant menu categories each of which contains menu items.
My property list file is fine. I am able to load the file and loop through the nodes structure creating NSEntityDescriptions and am able to save to Core Data. Everything works fine and expectedly except that in my menu category managed object, I have an NSArray of menu items for that category. Later on, when I fetch the categories, the pointers to the menu items in a category is lost and I get all the menu items. Am I suppose to be using predicates or does Core Data keep track of my object graph for me?
Can anyone look at how I am loading Core Data and point out the flaw in my logic? I'm pretty good with either SQL and OOP by themselves, but am a little bewildered by ORM. I thought that I should just be able to use aggregation in my managed objects and that the framework would keep track of the pointers for me, but apparently not.
NSError *error;
NSURL *url = [NSURL URLWithString:#"http://foo.com"];
NSArray *categories = [[NSArray alloc] initWithContentsOfURL:url];
NSMutableArray *menuCategories = [[NSMutableArray alloc] init];
for (int i=0; i<[categories count]; i++){
MenuCategory *menuCategory = [NSEntityDescription
insertNewObjectForEntityForName:#"MenuCategory"
inManagedObjectContext:[self managedObjectContext]];
NSDictionary *category = [categories objectAtIndex:i];
menuCategory.name = [category objectForKey:#"name"];
NSArray *items = [category objectForKey:#"items"];
NSMutableArray *menuItems = [[NSMutableArray alloc] init];
for (int j=0; j<[items count]; j++){
MenuItem *menuItem = [NSEntityDescription
insertNewObjectForEntityForName:#"MenuItem"
inManagedObjectContext:[self managedObjectContext]];
NSDictionary *item = [items objectAtIndex:j];
menuItem.name = [item objectForKey:#"name"];
menuItem.price = [item objectForKey:#"price"];
menuItem.image = [item objectForKey:#"image"];
menuItem.details = [item objectForKey:#"details"];
[menuItems addObject:menuItem];
}
[menuCategory setValue:menuItems forKey:#"menuItems"];
[menuCategories addObject:menuCategory];
[menuItems release];
}
if (![[self managedObjectContext] save:&error]) {
NSLog(#"An error occurred: %#", [error localizedDescription]);
}
You set a NSArray as to-many relationship object
NSMutableArray *menuItems = [[NSMutableArray alloc] init];
[menuCategory setValue:menuItems forKey:#"menuItems"];
which might cause the trouble.(should throw an exception?) Relationships in CoreData are always unsorted, therefore NSSets. Add a sortIndex property to your entities for ordering.
I had the same issue. There are 2 major problems with using NSSets and Core Data: if you need non-distinct objects and need them ordered. As an example, say you have 2 entities in Core Data: professor and student. The student takes 10 classes for a degree program and you wish to have a (one-to-many) relationship from the student to the professor in order that the classes were taken. Also, the same professor may teach more than one class. This was how I overcame the issue. Create a Binary Data attribute (we'll call it profData) in student and store dictionaries that make it possible to reconstruct the data as needed. Note: don't store an array of professors, since they inherit from NSManagedObject vs. NSObject. That can cause problems. You can bolt on the required methods using a category. In this example, I created a category on Student called ProfList (Student+ProfList.h/m). This keeps the code out of the NSManagedObject subclasses, so if my attributes in Core Data change, I can regenerate the subclasses automatically without wiping out this code. Here is some sample code:
// Student+ProfList.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import "Student.h"
#import "Professor.h"
#interface Student (ProfList)
- (NSArray *)getStudentsFullList;
- (void)storeStudentsFullList:(NSArray *)fullList;
#end
// Student+ProfList.m
#import "Student+ProfList.h"
#implementation Student (ProfList)
- (NSArray *)getStudentsFullList
{
NSData *storedData = self.profData;
if (!storedData) return nil;
NSMutableArray *fullList = [[NSMutableArray alloc] init];
// Retrieve any existing data
NSArray *arrayOfDictionaries = [NSKeyedUnarchiver unarchiveObjectWithData:storedData];
// Get the full professor list to pull from when recreating object array
NSManagedObjectContext *context = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"Professor"];
NSSortDescriptor *alphaSort =
[[NSSortDescriptor alloc] initWithKey:#"name"
ascending:YES
selector:#selector(localizedCaseInsensitiveCompare:)];
[fetchRequest setSortDescriptors:#[alphaSort]];
NSSet *allProfessors = [NSSet setWithArray:[context executeFetchRequest:fetchRequest error:nil]];
for (NSDictionary *dict in arrayOfDictionaries) {
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"name LIKE %#", [dict objectForKey:#"name"]];
NSSet *filteredSet = [allProfessors filteredSetUsingPredicate:predicate];
Professor *newProfessor = [filteredSet anyObject];
newProfessor.index = [dict objectForKey:#"index"];
[fullList addObject:newProfessor];
}
return fullList;
}
- (void)storeStudentsFullList:(NSArray *)fullList
{
NSMutableArray *encodedList = [[NSMutableArray alloc] init];
for (Professor *professor in fullList) {
[encodedList addObject:#{#"index" : #([encodedList count]), #"name" : professor.name}];
}
NSArray *encodedArray = [NSArray arrayWithArray:encodedList];
NSData *arrayData = [NSKeyedArchiver archivedDataWithRootObject:encodedArray];
self.profData = arrayData;
}
#pragma mark - Core Data
- (NSManagedObjectContext *)managedObjectContext
{
NSManagedObjectContext *context = nil;
id delegate = [[UIApplication sharedApplication] delegate];
if ([delegate performSelector:#selector(managedObjectContext)]) {
context = [delegate managedObjectContext];
}
return context;
}
#end
You store a local variable in a view controller, then send this message to the student instance to get the list and save it locally for use in a table view or whatever.
Related
I want to insert 200 5Mb records in my Core Database. But when I save the NSManagedObject, the memory wasn't released (autoreleased pool didn't help), and after inserting 30 records I got the memory warning and the application crashed. Here is my code
- (void)SaveItem
{
NSString *entityName = kEntityName;
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = appDelegate.managedObjectContext;
NSEntityDescription *entityDesctiption = [NSEntityDescription
entityForName: entityName
inManagedObjectContext:context];
// check if town exists
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"id == %d", self.imageID];
NSFetchRequest *requestToCheckExistense = [[NSFetchRequest alloc] init];
[requestToCheckExistense setEntity:entityDesctiption];
[requestToCheckExistense setPredicate:predicate];
NSArray *objects = [context executeFetchRequest:requestToCheckExistense error:nil];
[requestToCheckExistense release];
if (objects == nil)
{
NSLog(#"there was an error");
}
NSManagedObject *object;
if ([objects count] > 0)
{
// edit item
object = [objects objectAtIndex:0];
}
else
{
// if object doesn't exist, find max id to imlement autoincrement
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entityDesctiption];
request.propertiesToFetch = [NSArray arrayWithObjects: #"id", nil];
NSArray *allobjects = [context executeFetchRequest:request error:nil];
[request release];
NSInteger newID = 1;
if ([allobjects count] > 0)
{
NSNumber *maxID = [allobjects valueForKeyPath:#"#max.id"];
newID = [maxID intValue] + 1;
}
// write item
object = [NSEntityDescription insertNewObjectForEntityForName:entityName inManagedObjectContext:context];
[object setValue:[NSNumber numberWithInt:newID] forKey:#"id"];
self.imageID = newID;
}
// fill NSManagedObject
// size of objNSData is about 5MB
NSMutableData *objNSData = [[DatabaseManager sharedDatabaseManager] encryptedDataFromImage:bigImage];
[object setValue:objNSData forKey:#"big"];
[context save:nil];
}
When I commented
[object setValue:objNSData forKey:#"big"];
everything was OK.
I tried to add the code into #autoreleasepool , but that didn't help.
I know, that now, when I save data to database, it's still in iPhone RAM. How to release it from this memory? When I get a set of Managed Objects from the database, they are not in the RAM (I can easyly get 100 object, each of them has 5Mb fields)
object =(tblEntity *) [NSEntityDescription insertNewObjectForEntityForName:entityName inManagedObjectContext:context];
try to type cast the object,this may solve the problem
I've solved the issue.
after call of [self SaveItem];
I used
[context save];
[context reset];
[context save];
all the NSManagedObjects from the context will be released.
After that operation I can add as many big objects as I want
Because you don't own an NSManagedObject when you create it, it may be retained by the core data stack even after releasing it (when using an autoreleasepool contained inside the loop).
This may help:
Set the undo manager of your managedobjectContext to nil:
[context setUndoManager:nil];
Be sure that no properties of that object are retained anywhere, because then the managed object will not be released on time inside your loop.
Be sure to add an autorelease pool inside every loop execution, not wrapping all the loop itself, similar to:
for(i;i<n;i++) {
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
[obj saveItem];
[pool drain];
}
If that object belongs to a hierarchy of NSManagedObjects, then you need to release the owner of this object too, for this one to be deallocated from memory.
You can check apple's documentation about memory management in CoreData.
Warning: big objects (> 1MB) are not recommended by Apple to be stored inside CoreData (Check this other question/answer.)
It seems crazy to me that I have all of these NSFetchRequests for the same NSManagedObjects spread out throughout different view controllers in my app, is there a good pattern for data access that puts what I need in a single place?
I agree it is a bit much, fortunately there is Active Record for Core Data. This makes fetching less tedious, for example, fetching all Person objects from core data would be as simple as
NSArray *people = [Person findAll];
Yes there is, it is called a facade pattern. Simply define a public method on your NSManagedObject subclass like so:
#interface Group : NSManagedObject { }
// … cruft here …
-(NSArray*)peopleSortedByName;
#end
And hide the nasty implementation like so:
-(NSArray*)peopleSortedByName;
{
NSFetchRequest* request = // … bla bla, lots of code here
return [[self managedObjectContext] executeFetchRequest:request
error:NULL];
}
Then use the method just as if the it was any other class in your code. Write once, relief everywhere.
Define a category method for NSManagedObject context which wrappers up a general query into a one-liner.
#interface NSManagedObjectContext(MyQueryAdditions)
-(NSArray *)queryEntityForName:(NSString *)name predicateFormat:(NSString *)pstring argumentArray:(NSArray *)arr;
#end
#implementation NSManagedObjectContext(MyQueryAdditions)
-(NSArray *)queryEntityForName:(NSString *)name predicateFormat:(NSString *)pstring argumentArray:(NSArray *)arr
{
NSEntityDescription *entity = [NSEntityDescription entityForName:name inManagedObjectContext:self];
NSFetchRequest *fetch = [[[NSFetchRequest alloc] init] autorelease];
[fetch setEntity:entity];
NSPredicate *pred;
if(pstring)
{
if(arr) pred = [NSPredicate predicateWithFormat:pstring argumentArray:arr];
else pred = [NSPredicate predicateWithFormat:pstring];
[fetch setPredicate:pred];
}
NSError *error = nil;
[self retain];
[self lock];
NSArray *results = [self executeFetchRequest:fetch error:&error];
if (error) {
NSLog(#"MOC Fetch - Unresolved error %#, %#", error, [error userInfo]);
results = [NSArray array];
}
[self unlock];
[self release];
return results;
}
#end
Means a basic all items query can be as simple as
NSArray *cres = [managedObjectContext queryEntityForName:#"Person" predicateFormat:nil argumentArray:nil];
I am writing an application that has four main entities that are all linked via relationships. Some are one to one, some are one to many. Upon initial load, three of the entities load their data from XML files stored locally to the application and one of the entities downloads an XML from the web and loads its data from it. When the app loads it performs a check to see if the data from each of these files is more recent than what it currently has and, if so, it will replace all current data in that entity with data from the appropriate file.
As part of my debug process during writing I have been forcing a delete of all data. When the delete function is called and all data is loaded at app launch the application runs beautifully and all entities and relationships behave exactly as they should. However, when I remove the call to the delete function and it performs the checks and tries to run from data it has stored, all of the relationships seem to disappear. In debugging this, I have found that all of the entities do contain all of the regular data that they are supposed to, they just don't have the relationships anymore. I can't figure out why in the world the relationships are saved on first load but don't retain when all data is not re-imported.
I would imagine some code would be helpful to anyone debugging, however, I'm not sure how much I should include. So, I will start by including just one of the methods called in the data loading class. If anything else would help, please let me know. Any help is very much appreciated.
UPDATED CODE: 2/25/11 (Based on Suggestions - Problem still exists)
UPDATED CODE: 2/25/11 - Problem Solved
- (NSArray *) loadFeatures {
if ([self checkForUpdate:#"Features"]) {
[self deleteAllObjects:#"Features"];
NSString *filePath = [self dataFilePath:FALSE withResourceName:#"Features"];
NSData *xmlData = [[NSMutableData alloc] initWithContentsOfFile:filePath];
NSError *error;
GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:xmlData options:0 error:&error];
NSArray *featureElements = [doc.rootElement elementsForName:#"FEATURE"];
NSMutableSet *featureSections = [[NSMutableSet alloc] init];
for (GDataXMLElement *featureElement in featureElements) {
NSString *featureName = nil;
NSNumber *featureSecure = nil;
NSNumber *featureID = nil;
NSNumber *featureSortKey = nil;
DisplayTypes *featureDisplayType = nil;
NSArray *names = [featureElement elementsForName:#"NAME"];
if (names.count > 0) {
GDataXMLElement *firstName = (GDataXMLElement *) [names objectAtIndex:0];
featureName = firstName.stringValue;
} else continue;
NSArray *secures = [featureElement elementsForName:#"SECURE"];
if (secures.count > 0) {
GDataXMLElement *firstSecure = (GDataXMLElement *) [secures objectAtIndex:0];
featureSecure = [NSNumber numberWithInt:firstSecure.stringValue.intValue];
} else continue;
NSArray *featureIDs = [featureElement elementsForName:#"FEATUREID"];
if (featureIDs.count > 0) {
GDataXMLElement *firstFeatureID = (GDataXMLElement *) [featureIDs objectAtIndex:0];
featureID = [NSNumber numberWithInt:firstFeatureID.stringValue.intValue];
}
NSArray *featureSortKeys = [featureElement elementsForName:#"SORTKEY"];
if (featureSortKeys.count > 0) {
GDataXMLElement *firstSortKey = (GDataXMLElement *) [featureSortKeys objectAtIndex:0];
featureSortKey = [NSNumber numberWithInt:firstSortKey.stringValue.intValue];
}
NSArray *featureDisplays = [featureElement elementsForName:#"DISPLAYTYPEID"];
if (featureDisplays.count > 0) {
GDataXMLElement *firstFeatureDisplay = (GDataXMLElement *) [featureDisplays objectAtIndex:0];
for (DisplayTypes *thisDisplayType in self.displayTypes) {
if (thisDisplayType.displayTypeID == [NSNumber numberWithInt:firstFeatureDisplay.stringValue.intValue]) {
featureDisplayType = thisDisplayType;
}
}
}
NSArray *sectionElements = [featureElement elementsForName:#"SECTIONS"];
for (GDataXMLElement *sectionElement in sectionElements) {
NSArray *sectionIDs = [sectionElement elementsForName:#"SECTION"];
for (GDataXMLElement *sectionID in sectionIDs) {
NSArray *thisSectionIDs = [sectionID elementsForName:#"SECTIONID"];
if ([thisSectionIDs count]) {
GDataXMLElement *thisSectionID = (GDataXMLElement *) [thisSectionIDs objectAtIndex:0];
for (Sections *thisSection in self.sections) {
if ([thisSection.sectionID isEqualToNumber:[NSNumber numberWithInt:thisSectionID.stringValue.intValue]]) {
[featureSections addObject:thisSection];
}
}
}
}
}
NSManagedObjectContext *context = [self managedObjectContext];
NSManagedObject *featureInfo = [NSEntityDescription insertNewObjectForEntityForName:#"Features" inManagedObjectContext:context];
[featureInfo setValue:featureName forKey:#"name"];
[featureInfo setValue:featureSecure forKey:#"secure"];
[featureInfo setValue:featureID forKey:#"featureID"];
[featureInfo setValue:featureSortKey forKey:#"sortKey"];
[featureInfo setValue:featureDisplayType forKey:#"display"];
[[featureInfo mutableSetValueForKey:#"section"] unionSet:featureSections];
NSError *error;
if (![context save:&error]) {
NSLog(#"Whoops, couldn't save: %#", [error localizedDescription]);
}
[[self.managedObjectContext objectWithID:featureDisplayType.objectID] addFeatureObject:featureInfo];
[self.managedObjectContext save:&error];
[featureSections removeAllObjects];
}
[xmlData release];
[doc release];
[featureSections release];
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Features" inManagedObjectContext:[self managedObjectContext]];
[fetchRequest setEntity:entity];
NSError *error;
NSArray *featureArray = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
[fetchRequest release];
return featureArray;
}
UPDATE: 5/25/2011
Per request I am posting a couple of screen shots.
1) This is what I get when the app loads after all data has been deleted and the relationships are in tact
2) This is what I get when the app runs again without first deleting and reloading data. The tabs at the bottom are created by one of the entities, and are titled a bit different. This happens because the relationship with the DisplayType is not present and it doesn't know what type of view controller to load and it doesn't know which icon to use for the tab.
Typically, you wouldn't need to explicitly set both sides of a relationship. When you're dealing with a to-many relationship, it's probably safer to add one entity at a time to the collection, instead of setting the collection all at once. So, instead of:
[featureInfo setValue:[NSSet setWithSet:featureSections] forKey:#"section"];
I would loop through the featureSections Set and add each object one by one to the section relationship of the Feature entity, e.g.:
for (Sections *aSection in featureSections) {
// use the automatically-generated relationship mutator
[featureInfo addSectionsObject:aSection];
}
I hope this helps...
Otherwise, this section in the Apple documentation might be of interest.
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:
Do I have to create an entity for each of my classes or just for "Game"?
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)..
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
What I recommend is to setup your database model in xcode, then when you have done that... choose the entities 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 entities should be generated to files.
After you have done that, you can implement the functions you need into your e.g. you delegate. My recommendation 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 other way 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.
Yes, you want to create an entity for all of the classes you mentioned.
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.
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];
I have a problem that whenever I'm inserting data using coredata, everything's going fine. But while retrieving, I'm getting the same object all the time retrieved. I'm inserting objects of actors with multiple attribues like id,name,address etc. in add method, I can see everything getting inserted(which actually I'm retrieving from an xml file). my set methods are like:=
[poi setActorCity:[NSString stringWithFormat:#"%#",[poi1 objectAtIndex:j]]];
where, poi is an object of my managedObjectClass POI1 . Are those a problem? & j index is simply for keeping track of xml values from poi1 array. Please help...
(void)addEvent
{
[actorsArray removeAllObjects];
NSEntityDescription *entity1 = [NSEntityDescription entityForName:#"POI1" inManagedObjectContext:self.managedObjectContext];
POI1 *poi = (POI1 *)[NSEntityDescription insertNewObjectForEntityForName:#"POI1" inManagedObjectContext:managedObjectContext];
for(NSInteger i=0;i<[Actors count];i++)
{
NSMutableArray *poi1=[[NSMutableArray alloc]init];
poi1=[Actors objectAtIndex:i];
for(int j=0;j<[poi1 count];j++)
{
if(j==1)
{
[poi setActorName:[NSString stringWithFormat:#"%#",[poi1 objectAtIndex:j]]];
} //Like this it inserts for every attribute
}
[actorsArray insertObject:poi atIndex:i];
[poi release];
}
[self saveAction]; //saving the managedObjectContext
}
This' my fetch method...
-(void)fetchResult
{
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity1 = [NSEntityDescription entityForName:#"POI1" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity1];
NSArray *items = [self.managedObjectContext
executeFetchRequest:fetchRequest error:&error];
for(NSInteger k=0;k<[items count];k++)
{
POI1 *_poi=[[POI1 alloc]init];
_poi = [items objectAtIndex:k];
NSString *str=[NSString stringWithFormat:#"%#",[_poi actorName]]; //This' for testing... Shows me same name every time..,
}
[fetchRequest release];
}
It sounds like you have a problem with your fetch. Check your predicate. If it returns the same object the most likely cause is that your predicate is written such that it only finds that one object.
Edit01:
This line is your problem:
POI1 *poi = (POI1 *)[NSEntityDescription insertNewObjectForEntityForName:#"POI1" inManagedObjectContext:managedObjectContext];
Despite the fact that the class called is 'NSEntityDescription' this method returns a managed object instance. Right now you create a single POI1instance and then just keep assigning it different attributes. You're seeing the same values because you've only created, populated and saved one object.
Move the object creation inside the loop:
for(NSInteger i=0;i<[Actors count];i++)
{
POI1 *poi = (POI1 *)[NSEntityDescription insertNewObjectForEntityForName:#"POI1" inManagedObjectContext:managedObjectContext];
NSMutableArray *poi1=[[NSMutableArray alloc]init];
poi1=[Actors objectAtIndex:i];
for(int j=0;j<[poi1 count];j++)
{
if(j==1)
{
[poi setActorName:[NSString stringWithFormat:#"%#",[poi1 objectAtIndex:j]]];
} //Like this it inserts for every attribute
}
[actorsArray insertObject:poi atIndex:i];
[poi release];
}
This will create a new POI1 at each pass so that the each element of the Actors array will have a corresponding POI1 instances containing its data.
A little hard to answer precisely with this information, but my educated guess would be that you do not create new poi instance every time and keep adding the same reference to your array.
Make sure that you're saving your managedObjectContext after doing all of those inserts(probably after each insert), otherwise the information will never leave temporary memory.