I have a plist of values I want to read into Core Data. I can read in the "top level," but along with strings and numbers, each item also contains dictionaries. I am having trouble getting the syntax right to read those.
Garden and Plant are my 2 Core Data Entities. Both Garden and Plant are NSDictionaries containing data about themselves. Gardens can contain many plants, and specific plants can be in many gardens, so there is a many to many relationship.
This much works:
I use a plist dictionary of gardens to populate my core database on firstRun, called from application finised launching like so:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if (![defaults objectForKey:@"firstRun"])
{
[defaults setObject:[NSDate date] forKey:@"firstRun"];
[[NSUserDefaults standardUserDefaults] synchronize];
[self loadGardenDataFromPlistDictionary];
}
That works. And so does the first level of loading the various plist values into core data. But I am having trouble loading data that is contained within the "plants" dictionary that is inside the "garden" dictionary... 2 levels deep. In other words, name, detail, and notes load... but plants do not. Here's my code so far:
-(void) loadGardenDataFromPlistDictionary{
// build path to plist; check Documents first, then Bundle.
NSArray *paths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [paths objectAtIndex:0];
NSString *plistPath = [documentsPath stringByAppendingPathComponent:@"defaultGardenDictionary.plist"];
if (![[NSFileManager defaultManager] fileExistsAtPath:plistPath])
{
// if not in documents, get property list from main bundle
plistPath = [[NSBundle mainBundle] pathForResource:@"defaultGardenDictionary" ofType:@"plist"];
}
// read property list into memory as an NSData object
NSData *plistXML = [[NSFileManager defaultManager] contentsAtPath:plistPath];
NSString *errorDesc = nil;
NSPropertyListFormat format;
// convert static property list into dictionary object
NSDictionary *plistDictionary = (NSDictionary *)[NSPropertyListSerialization propertyListFromData:plistXML mutabilityOption:NSPropertyListMutableContainersAndLeaves format:&format errorDescription:&errorDesc];
if (!plistDictionary)
{
NSLog(@"Error reading plist: %@, format: %d", errorDesc, format);
}
NSManagedObjectContext *context = self.managedObjectContext;
[plistDictionary enumerateKeysAndObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(id key, id object, BOOL *stop) {
NSManagedObject *gardenManObj = [NSEntityDescription insertNewObjectForEntityForName:@"Garden" inManagedObjectContext:context];
[gardenManObj setValue:[thisGardenDictionary objectForKey:@"name"] forKey:@"name"];
[gardenManObj setValue:[thisGardenDictionary objectForKey:@"detail"] forKey:@"detail"];
[gardenManObj setValue:[thisGardenDictionary objectForKey:@"notes"] forKey:@"notes"];
[gardenManObj setValue:[thisGardenDictionary objectForKey:@"rating"] forKey:@"rating"];
NSDictionary *thisGardenPlantsDictionary = [thisGardenDictionary objectForKey:@"plants"];
NSLog(@"thisGardenPlantsDictionary contains %i dictionaries.", [thisGardenPlantsDic开发者_JAVA百科tionary count]);
//The trace statement above shows the correct number of plants in each garden dictionary. oooh... so tantalizingly close!
//However, the next item is the dictionary of plants in this garden. It comes up blank.
//I don't understand the syntax to load that dictionary of plants into its corresponding dictionary of plants within a garden in core data.
//I deleted most of the things I've tried and failed with so far. Here's my last attempt:
// the obvious and parallel:
[gardenManObj setValue:[thisGardenDictionary objectForKey:@"plants"] forKey:@"plants"];
//did not work; xCode compiler objected to "incompatible pointer types."
//the compiler seemed to want an NSSet, so I tried:
NSSet *thisGardenPlantsSet = [thisGardenDictionary mutableSetValueForKey:@"steps"];
NSLog(@"thisGardenPlantsSet contains %i sets.", [thisGardenPlantsSet count]);
[gardenManObj setValue:thisGardenPlantsSet forKey:@"steps"];
//the compiler was fooled, but the setValue crashed at runtime.
}];
}
What am I missing?
You are not creating a new managed object for each Plant
dictionary value. You are just trying to assign the dictionary itself to the relationship which, of course, will not work.
You need to add something like:
[gardenManObj setValue:[thisGardenDictionary objectForKey:@"rating"] forKey:@"rating"];
NSDictionary *thisGardenPlantsDictionary = [thisGardenDictionary objectForKey:@"plants"];
NSLog(@"thisGardenPlantsDictionary contains %i dictionaries.", [thisGardenPlantsDictionary count]);
NSManagedObject *plantMO;
for (Plant *eachPlant in thisGardenPlantsDictionary) {
plantMO=[NSEntityDescription insertNewObjectForEntityForName:@"Plant" inManagedObjectContext:context];
[plantMO setValue:[eachPlant valueForKey:@"someValue" forKey:@"someKey"]];
//... repeat for all attributes
[plantMO setValue:gardenManObj forKey:@"gardent"];
}
... that will create the necessary Plant
objects and set the relationship with the correct Garden
object.
精彩评论