core data simple fetch request template - core-data

I have a small core data base "Guests" and I am trying to get the results from a fetch request template called FetchRequestA, I made a button to trigger in the console the results from the request but I keep on getting a null answer, the request is set to display all guestlastnames that contain a d ? here is the code that i am using :
- (IBAction)fetchA:(id)sender {
NSFetchRequest *request2 = [[[self managedObjectModel] fetchRequestTemplateForName:#"FetchRequestA"] copy];
NSSortDescriptor *sort = [[NSSortDescriptor alloc]initWithKey:#"guestlastname" ascending:YES];
[request2 setSortDescriptors:[NSArray arrayWithObject:sort]];
NSArray *sortDescriptors = [[NSArray alloc]initWithObjects:sort, nil];
[request2 setSortDescriptors:sortDescriptors];
NSError *error = nil;
NSArray *fetchedObjects = [[self managedObjectContext] executeFetchRequest:request2 error:&error];
if (fetchedObjects == nil) {
NSLog(#"problem %#", error);
}
for (Guests *guestlastname in fetchedObjects) {
NSLog(#"Fetched Object = %#", guestlastname.guestlastname);
}
}
Am I missing a method ? have perused around but to no avail, thanks in advance.

Here is solution :
(IBAction)gettemplatebutton:(id)sender {
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSManagedObjectModel* model = [[context persistentStoreCoordinator] managedObjectModel];
NSDictionary* dict = [[NSDictionary alloc]initWithObjectsAndKeys: self.fetchedObjects, #"guestlastname",nil];
NSFetchRequest* request2 = [model fetchRequestFromTemplateWithName:#"FetchRequestA" substitutionVariables: dict];
NSError* error = nil;
NSArray *Guests2 = [context executeFetchRequest:request2 error:&error];
NSString *g3 = #"";
for(NSManagedObject *guestlastname in Guests2)
{
g3 = [g3 stringByAppendingString:[NSString stringWithFormat:#"%#\n", [guestlastname valueForKey:#"guestlastname"]]];
}
self.displaytemplateLabel.text = g3;
[_displaytemplateLabel setNumberOfLines:0];
for (NSManagedObject *guestlastname in Guests2)
{
{
NSLog(#"%#", [guestlastname valueForKey:#"guestlastname"]);
}
}
}
and added #property (nonatomic, retain) NSArray *fetchedObjects; in header file.

Related

Core Data properties based upon relationships returning NULL

I have a Core Data data model such as
I want to display the Teams.name associated with each Batting object in my UITableViewCell. When I try to access batting.teams.name it returns NULL.
My opening view controller has a string passed in then creates a new viewController with NSPredicate based from Master.nameLast and lists all names matching
and the NSFetchedResultsController which created the above list
#pragma mark - Fetched Results Controller Section
- (NSFetchedResultsController *)fetchedResultsController {
if(_fetchedResultsController != nil) {
return _fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSManagedObjectContext *context = [self managedObjectContext];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Master" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"debut" ascending:YES];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"nameLast = [c]%#", lastName];
[fetchRequest setPredicate:predicate];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
fetchRequest.sortDescriptors = sortDescriptors;
_fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:context sectionNameKeyPath:nil cacheName:nil];
return _fetchedResultsController;
}
My next view controller then lists all Batting properties associated with the selected Master NSManagedObject.
But when I try to access batting.teams.name it returns NULL!!!!! If I NSLog the entity from my delegate they are set but I can't access Teams.name from it's Batting.teams relationship
#pragma mark - Fetched Results Controller Section
- (NSFetchedResultsController *)fetchedResultsController {
if(_fetchedResultsController != nil) {
return _fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSManagedObjectContext *context = [self managedObjectContext];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Batting" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"yearID" ascending:YES];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"playerID = %# " , selectedMaster.playerID];
[fetchRequest setPredicate:predicate];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
fetchRequest.sortDescriptors = sortDescriptors;
_fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:context sectionNameKeyPath:nil cacheName:nil];
return _fetchedResultsController;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"playerStats" forIndexPath:indexPath];
Batting *batting = [self.fetchedResultsController objectAtIndexPath:indexPath];
NSString *team = batting.teams.name; //NULL NULL NULL
// Configure the cell...
double average = [batting.h doubleValue]/[batting.ab doubleValue];
NSString *averageStr = [[NSString stringWithFormat:#"%.3f", average] substringFromIndex:1];
cell.textLabel.text = [NSString stringWithFormat:#"%# %#", batting.yearID, batting.teams.name];
cell.detailTextLabel.text = [NSString stringWithFormat:#"H: %#, AVG: %#, HR: %#, RBI: %#, SB: %#, R: %#, BB: %#, K: %#",
batting.h, averageStr , batting.hr, batting.rbi, batting.sb, batting.r, batting.bb, batting.so];
cell.detailTextLabel.textColor = [UIColor grayColor];
return cell;
}
returns null for the second argument????????
cell.textLabel.text = [NSString stringWithFormat:#"%# %#", batting.yearID, batting.teams.name];
and this is the Teams entity logged from the AppDelegate
//
// AppDelegate.m
// Baseball Stats
//
// Created by Jason Steindorf on 6/6/15.
// Copyright (c) 2015 Jason Steindorf. All rights reserved.
//
#import "AppDelegate.h"
#import "Master.h"
#import "Teams.h"
#import "Batting.h"
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
NSError *error;
NSString* dataPath_MASTER = [[NSBundle mainBundle] pathForResource:#"master" ofType:#"json"];
NSArray* MASTER = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:dataPath_MASTER]
options:kNilOptions
error:&error];
NSString* dataPath_TEAMS = [[NSBundle mainBundle] pathForResource:#"teams" ofType:#"json"];
NSArray* TEAMS = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:dataPath_TEAMS]
options:kNilOptions
error:&error];
NSString* dataPath_ABC = [[NSBundle mainBundle] pathForResource:#"abc" ofType:#"json"];
NSArray* BATTING_ABC = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:dataPath_ABC]
options:kNilOptions
error:&error];
NSString* dataPath_DEFGH = [[NSBundle mainBundle] pathForResource:#"defgh" ofType:#"json"];
NSArray* BATTING_DEFGH = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:dataPath_DEFGH]
options:kNilOptions
error:&error];
NSString* dataPath_IJKLM = [[NSBundle mainBundle] pathForResource:#"ijklm" ofType:#"json"];
NSArray* BATTING_IJKLM = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:dataPath_IJKLM]
options:kNilOptions
error:&error];
NSString* dataPath_NOPQR = [[NSBundle mainBundle] pathForResource:#"nopqr" ofType:#"json"];
NSArray* BATTING_NOPQR = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:dataPath_NOPQR]
options:kNilOptions
error:&error];
NSString* dataPath_ST = [[NSBundle mainBundle] pathForResource:#"st" ofType:#"json"];
NSArray* BATTING_ST = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:dataPath_ST]
options:kNilOptions
error:&error];
NSString* dataPath_UVWXYZ = [[NSBundle mainBundle] pathForResource:#"uvwxyz" ofType:#"json"];
NSArray* BATTING_UVWXYZ = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:dataPath_UVWXYZ]
options:kNilOptions
error:&error];
// Test listing all Master from the store
NSFetchRequest *fetchRequestMaster = [[NSFetchRequest alloc] init];
NSEntityDescription *entityMaster = [NSEntityDescription entityForName:#"Master" inManagedObjectContext:self.managedObjectContext];
[fetchRequestMaster setEntity:entityMaster];
NSArray *fetchedObjectsMaster = [self.managedObjectContext executeFetchRequest:fetchRequestMaster error:&error];
NSLog(#"Number of records in master.json - %d", (int)[fetchedObjectsMaster count]);
for (id m in MASTER) {
Master *master = [NSEntityDescription insertNewObjectForEntityForName:#"Master"
inManagedObjectContext:self.managedObjectContext];
master.nameFirst = [m objectForKey:#"nameFirst"];
master.nameLast = [m objectForKey:#"nameLast"];
master.debut = [m objectForKey:#"debut"];
master.playerID = [m objectForKey:#"playerID"];
NSError *error;
if (![self.managedObjectContext save:&error]) {
NSLog(#"Whoops, couldn't save: %#", [error localizedDescription]);
}
}
fetchedObjectsMaster = [self.managedObjectContext executeFetchRequest:fetchRequestMaster error:&error];
for (Master *master in fetchedObjectsMaster) {
NSLog(#"first name: %#", master.nameFirst);
NSLog(#"last name: %#", master.nameLast);
NSLog(#"debut: %#", master.debut);
NSLog(#"playerID: %#\n\n", master.playerID);
}
// Test listing all Master from the store
NSFetchRequest *fetchRequestTeams = [[NSFetchRequest alloc] init];
NSEntityDescription *entityTeams = [NSEntityDescription entityForName:#"Teams" inManagedObjectContext:self.managedObjectContext];
[fetchRequestTeams setEntity:entityTeams];
NSArray *fetchedObjectsTeams = [self.managedObjectContext executeFetchRequest:fetchRequestTeams error:&error];
NSLog(#"Number of records in teams.json - %d", (int)[fetchedObjectsTeams count]);
for (id t in TEAMS) {
Teams *team = [NSEntityDescription insertNewObjectForEntityForName:#"Teams"
inManagedObjectContext:self.managedObjectContext];
team.name = [t objectForKey:#"name"];
team.minYearID = [t objectForKey:#"minYearID"];
team.maxYearID = [t objectForKey:#"maxYearID"];
team.teamID = [t objectForKey:#"teamID"];
NSError *error;
if (![self.managedObjectContext save:&error]) {
NSLog(#"Whoops, couldn't save: %#", [error localizedDescription]);
}
}
fetchedObjectsTeams = [self.managedObjectContext executeFetchRequest:fetchRequestTeams error:&error];
for (Teams *team in fetchedObjectsTeams) {
NSLog(#"name: %#", team.name);
NSLog(#"minYearID: %#", team.minYearID);
NSLog(#"maxYearID: %#", team.maxYearID);
NSLog(#"teamID: %#\n\n", team.teamID);
}
NSFetchRequest *fetchRequestBatting = [[NSFetchRequest alloc] init];
NSEntityDescription *entityBatting = [NSEntityDescription entityForName:#"Batting" inManagedObjectContext:self.managedObjectContext];
[fetchRequestBatting setEntity:entityBatting];
NSArray *fetchedObjectsBatting = [self.managedObjectContext executeFetchRequest:fetchRequestBatting error:&error];
NSLog(#"Number of records in battingFiles.json - %d", (int)[fetchedObjectsBatting count]);
for (id b in BATTING_UVWXYZ) {
Batting *batting = [NSEntityDescription insertNewObjectForEntityForName:#"Batting"
inManagedObjectContext:self.managedObjectContext];
batting.playerID = [b objectForKey:#"playerID"];
batting.h = [b objectForKey:#"h"];
batting.ab = [b objectForKey:#"ab"];
batting.hr = [b objectForKey:#"hr"];
batting.rbi = [b objectForKey:#"rbi"];
batting.sb = [b objectForKey:#"sb"];
batting.r = [b objectForKey:#"r"];
batting.bb = [b objectForKey:#"bb"];
batting.so = [b objectForKey:#"so"];
batting.yearID = [b objectForKey:#"yearID"];
batting.teamID = [b objectForKey:#"teamID"];
NSError *error;
if (![self.managedObjectContext save:&error]) {
NSLog(#"Whoops, couldn't save: %#", [error localizedDescription]);
}
}
fetchedObjectsBatting = [self.managedObjectContext executeFetchRequest:fetchRequestBatting error:&error];
for (Batting *b in fetchedObjectsBatting) {
NSLog(#"playerID: %#", b.playerID);
NSLog(#"h: %#", b.h);
NSLog(#"ab: %#", b.ab);
NSLog(#"hr: %#", b.hr);
NSLog(#"rbi: %#", b.rbi);
NSLog(#"sb: %#", b.sb);
NSLog(#"r: %#", b.r);
NSLog(#"bb: %#", b.bb);
NSLog(#"so: %#", b.so);
NSLog(#"yearID: %#", b.yearID);
NSLog(#"teamID: %#\n\n", b.teamID);
}
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
- (void)applicationWillTerminate:(UIApplication *)application {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
// Saves changes in the application's managed object context before the application terminates.
[self saveContext];
}
#pragma mark - Core Data stack
#synthesize managedObjectContext = _managedObjectContext;
#synthesize managedObjectModel = _managedObjectModel;
#synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
- (NSURL *)applicationDocumentsDirectory {
// The directory the application uses to store the Core Data store file. This code uses a directory named "steindorf.Baseball_Stats" in the application's documents directory.
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
- (NSManagedObjectModel *)managedObjectModel {
// The managed object model for the application. It is a fatal error for the application not to be able to find and load its model.
if (_managedObjectModel != nil) {
return _managedObjectModel;
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"Baseball_Stats" withExtension:#"momd"];
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return _managedObjectModel;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
// The persistent store coordinator for the application. This implementation creates and return a coordinator, having added the store for the application to it.
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
// Create the coordinator and store
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"Baseball_Stats.sqlite"];
NSLog(#"%#", storeURL);
NSError *error = nil;
NSString *failureReason = #"There was an error creating or loading the application's saved data.";
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
// Report any error we got.
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
dict[NSLocalizedDescriptionKey] = #"Failed to initialize the application's saved data";
dict[NSLocalizedFailureReasonErrorKey] = failureReason;
dict[NSUnderlyingErrorKey] = error;
error = [NSError errorWithDomain:#"YOUR_ERROR_DOMAIN" code:9999 userInfo:dict];
// Replace this with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return _persistentStoreCoordinator;
}
- (NSManagedObjectContext *)managedObjectContext {
// Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.)
if (_managedObjectContext != nil) {
return _managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (!coordinator) {
return nil;
}
_managedObjectContext = [[NSManagedObjectContext alloc] init];
[_managedObjectContext setPersistentStoreCoordinator:coordinator];
return _managedObjectContext;
}
#pragma mark - Core Data Saving support
- (void)saveContext {
NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
if (managedObjectContext != nil) {
NSError *error = nil;
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
}
#end
In the block below, you need to assign the team to batting.
batting.teams = {your_team_object}
Then you will be able to access the team information. You can create another fetch to Core Data using the teamID to retrieve the team object.
for (id b in BATTING_UVWXYZ) {
Batting *batting = [NSEntityDescription insertNewObjectForEntityForName:#"Batting"
inManagedObjectContext:self.managedObjectContext];
batting.playerID = [b objectForKey:#"playerID"];
batting.h = [b objectForKey:#"h"];
batting.ab = [b objectForKey:#"ab"];
batting.hr = [b objectForKey:#"hr"];
batting.rbi = [b objectForKey:#"rbi"];
batting.sb = [b objectForKey:#"sb"];
batting.r = [b objectForKey:#"r"];
batting.bb = [b objectForKey:#"bb"];
batting.so = [b objectForKey:#"so"];
batting.yearID = [b objectForKey:#"yearID"];
batting.teamID = [b objectForKey:#"teamID"];
NSPredicate *teamIDPredicate = [NSPredicate predicateWithFormat:#"teamID == %#", [b objectForKey:#"teamID"]];
[fetchRequestTeams setPredicate:predicate];
NSArray *fetchedSpecificTeam = [self.managedObjectContext executeFetchRequest:fetchRequestTeams error:&error];
batting.teams= [fetchedSpecificTeam objectAtIndex:0];
NSError *error;
if (![self.managedObjectContext save:&error]) {
NSLog(#"Whoops, couldn't save: %#", [error localizedDescription]);
}
}

coredata subquery with multiple conditions / relations

I have the following model:
how can I get all the PT objects where groupId == '2'?
I have tried several ways, but without success.
With this query, I get one result only:
NSFetchRequest *request = [[NSFetchRequest alloc] init];
request.entity = [NSEntityDescription entityForName:#"Status" inManagedObjectContext:self.managedObjectContext];
request.predicate = [NSPredicate predicateWithFormat:#"group.groupId == %#", [NSNumber numberWithInt:2]];
NSError *error = nil;
NSArray *resultSet = [self.managedObjectContext executeFetchRequest:request error:&error];
[request release];
NSLog(#"array count: %lu", (unsigned long)[resultSet count]);
NSPredicate *thePredicate = [NSPredicate predicateWithFormat:#"hasBeenDeleted == %# AND (ANY hasStatus IN %#)",
[NSNumber numberWithBool:NO],
[NSSet setWithArray:resultSet]];
[self.ptListViewController refreshDataWithPredicate:thePredicate];
You could start with a template "GROUP_BY_GROUP_ID" and add it to the managedObjectModel ...
- (NSManagedObjectModel *)managedObjectModel {
// The managed object model for the application. It is a fatal error for the application not to be able to find and load its model.
if (_managedObjectModel != nil) {
return _managedObjectModel;
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"GroupdId2" withExtension:#"momd"];
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
NSFetchRequest *tmpTemplate;
NSEntityDescription *tmpEntity;
NSPredicate *tmpPredicate;
// 1. GROUP_BY_GROUP_ID
tmpEntity = [[_managedObjectModel entitiesByName] objectForKey:#"Group"];
tmpTemplate = [[NSFetchRequest alloc] init];
[tmpTemplate setEntity:tmpEntity];
tmpPredicate = [NSPredicate predicateWithFormat:#"(groupId == $value)"];
[tmpTemplate setPredicate:tmpPredicate];
[_managedObjectModel setFetchRequestTemplate:tmpTemplate forName:#"GROUP_BY_GROUP_ID"];
return _managedObjectModel;
}
Here is the appropriate fetch method:
- (NSArray *)fetchGroupByGroupId:(NSNumber *)value
{
NSError *error = nil;
NSManagedObjectModel *model = _managedObjectModel;
NSDictionary *substitutionDictionary = [NSDictionary dictionaryWithObjectsAndKeys:value, #"value", nil];
NSFetchRequest *fetchRequest = [model fetchRequestFromTemplateWithName:#"GROUP_BY_GROUP_ID" substitutionVariables:substitutionDictionary];
NSArray *results = [_managedObjectContext executeFetchRequest:fetchRequest error:&error];
return results;
}
Now you can start fetching PT entities like this (Xcode lets you generate the NSManagedObject subclasses for all entities):
NSArray *groups=[self fetchGroupByGroupId:#(2)];
NSMutableSet *resultPT=[[NSMutableSet alloc] init];
for (Group *group in groups) {
for (Status *status in group.hasStatus) {
for (PTStatus *ptstatus in status.ptStatus) {
if (ptstatus.targetPT!=nil) {
[resultPT addObject:ptstatus.targetPT];
}
if (ptstatus.pt!=nil) {
[resultPT addObject:ptstatus.pt];
}
}
}
}
In resultPT now you will find all different PT entities "with" groupId == '2'.
You find a XCode 6.1 project here: XCode 6.1 project on Dropbox.
Hope it helps.
I found it!
I had a bug when relating the Status with the Group.
Correct code for achieving:
NSFetchRequest *request = [[NSFetchRequest alloc] init];
request.entity = [NSEntityDescription entityForName:#"PTStatus" inManagedObjectContext:self.managedObjectContext];
request.predicate = [NSPredicate predicateWithFormat:#"ANY status.group.groupId == %#", [NSNumber numberWithInt:2]];
NSError *error = nil;
NSArray *resultSet = [self.managedObjectContext executeFetchRequest:request error:&error];
[request release];
NSLog(#"array count: %lu", (unsigned long)[resultSet count]);
NSPredicate *thePredicate = [NSPredicate predicateWithFormat:#"hasBeenDeleted == %# AND (ANY hasStatus IN %#)",
[NSNumber numberWithBool:NO],
[NSSet setWithArray:resultSet]];
[self.ptListViewController refreshDataWithPredicate:thePredicate];
and [self.ptListViewController refreshDataWithPredicate:thePredicate]; has
- (void)refreshDataWithPredicate:(NSPredicate *)predicate{
self.fetchedResultsController = nil;
[NSFetchedResultsController deleteCacheWithName:#"PTs_Cache"];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
request.entity = [NSEntityDescription entityForName:#"PT" inManagedObjectContext:self.managedObjectContext];
request.sortDescriptors = [NSArray arrayWithObjects:
[NSSortDescriptor sortDescriptorWithKey:#"requestDate" ascending:NO],
[NSSortDescriptor sortDescriptorWithKey:#"number" ascending:YES],
nil];
request.predicate = predicate;
request.fetchBatchSize = 40;
NSString *sectionNameKeyPathString = #"dateSection_transient";
NSFetchedResultsController *frc = [[NSFetchedResultsController alloc] initWithFetchRequest:request
managedObjectContext:self.managedObjectContext
sectionNameKeyPath:sectionNameKeyPathString
cacheName:#"PTs_Cache"];
[request release];
self.fetchedResultsController = frc;
[frc release];
[self.theTable reloadData];
}

Core-Data: Very confused by the implementation of multiple NSManagedObjects and an NSFetchedResultsController in a multithreading iOS app

I have a routine that fetches RSS entries in the background and insert these in my NSManagedObjectContext if not already there.
My problem is that this object doesn't find duplicates or crashes, depending on which NSManagedObjectContext I use... Help me, please.
Here's the simplified .h
#interface AsyncFetchEngine : NSObject <NSXMLParserDelegate,NSFetchedResultsControllerDelegate>
#property (strong, nonatomic) dispatch_queue_t rssParserQueue;
#property (strong, nonatomic) NSMutableArray *uRLsToFetch;
#property (strong, nonatomic) NSManagedObjectContext *managedObjectContext;
#property (strong, nonatomic) NSManagedObjectContext *childManagedObjectContext;
#property (strong, nonatomic) NSFetchedResultsController *fetchedResultsController;
- (Boolean) isAlreadyInTheFetchQueue:(Feed *)feed;
- (void) fetchPosts:(Feed *)feed;
- (void) createPostInFeed:(Feed*)feed withTitle:(NSString *)title withContent:(NSString *)content withURL:(NSString *)url withDate:(NSDate *)date;
Now here's the init method:
Note if I set the _childManagedObjectContext's parent here, the program crashes.
-(AsyncFetchEngine *)init
{
_rssParserQueue = dispatch_queue_create("com.example.MyQueue", NULL);
_uRLsToFetch = [[NSMutableArray alloc] initWithCapacity:32];
_childManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[_childManagedObjectContext setPersistentStoreCoordinator:[_managedObjectContext persistentStoreCoordinator]];
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self
selector:#selector(contextDidSave:)
name:NSManagedObjectContextDidSaveNotification
object:_childManagedObjectContext];
return self;
}
- (void)contextDidSave:(NSNotification*)notification
{
void (^mergeChanges) (void) = ^ {
[_managedObjectContext mergeChangesFromContextDidSaveNotification:notification];
};
if ([NSThread isMainThread]) {
mergeChanges();
} else {
dispatch_sync(dispatch_get_main_queue(), mergeChanges);
}
}
Fetch method:
Note: not sure which MOC to use to determine localFeed, _managedObjectContext crashes the app.
- (void) fetchPosts:(Feed *)feed
{
if (!_childManagedObjectContext.parentContext) {
[_childManagedObjectContext setParentContext:self.managedObjectContext];
}
if ([self isAlreadyInTheFetchQueue:feed]) {
NSLog(#"AsyncFetchEngine::fetchPosts> \"%#\" is already in the fetch queue", feed.name);
return;
}
[_uRLsToFetch addObject:feed];
NSURL *url=[NSURL URLWithString:feed.rss];
NSURLRequest *req = [[NSURLRequest alloc] initWithURL:url];
if (![NSURLConnection canHandleRequest:req]) {
return;
}
Feed *localFeed = ((Feed *)[_childManagedObjectContext existingObjectWithID:[feed objectID] error:nil]);
dispatch_async(_rssParserQueue, ^{
NSLog(#"AsyncFetchEngine::fetchPosts> Opening %#", feed.rss);
[RSSParser parseRSSFeedForRequest:req success:^(NSArray *feedItems)
{
for(RSSItem *i in feedItems)
{
[self createPostInFeed:localFeed withTitle:i.title withContent:(i.content?i.content:i.itemDescription) withURL:[i.link absoluteString] withDate:(i.pubDate?i.pubDate:[NSDate date])];
}
NSLog(#"AsyncFetchEngine::fetchPosts> Found %d items", [feedItems count]);
[_uRLsToFetch removeObject:feed];
}
failure:^(NSError *error)
{
NSLog(#"AsyncFetchEngine::fetchPosts> RSSParser lost it: %#", [error localizedDescription]);
}];
});
}
- (Boolean) isAlreadyInTheFetchQueue:(Feed *)feed
{
Feed *f=nil;
for (f in _uRLsToFetch) {
if ([f isEqual:feed]){
return YES;
}
}
return NO;
}
NSFecthedResultsController, do I need it that way?
- (NSFetchedResultsController *)fetchedResultsController
{
if (_fetchedResultsController != nil) {
return _fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Edit the entity name as appropriate.
// Note: I originally tried to use the main MOC here, but it also used to crash the app.
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Post" inManagedObjectContext:_childManagedObjectContext];
[fetchRequest setEntity:entity];
// Set the batch size to a suitable number.
[fetchRequest setFetchBatchSize:20];
// Edit the sort key as appropriate.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"date" ascending:NO];
NSArray *sortDescriptors = #[sortDescriptor];
[fetchRequest setSortDescriptors:sortDescriptors];
/* NSPredicate *predicate =[NSPredicate predicateWithFormat:#"feed.rss LIKE '%#'", _detailItem.rss];
[fetchRequest setPredicate:predicate]; */
// Edit the section name key path and cache name if appropriate.
// nil for section name key path means "no sections".
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:nil];
aFetchedResultsController.delegate = self;
_fetchedResultsController = aFetchedResultsController;
return _fetchedResultsController;
}
It usually crashes somewhere in this method, according to the dump stack.
If it doesn't crash, I have my post added to a (null) Category...
- (void)createPostInFeed:(Feed*)feed withTitle:(NSString *)title withContent:(NSString *)content withURL:(NSString *)url withDate:(NSDate *)date
{
[_childManagedObjectContext performBlockAndWait:^{
NSError *error = nil;
if (![self.fetchedResultsController performFetch:&error]) {
NSLog(#"Error in refetch: %#",[error localizedDescription]);
abort();
}
}];
NSLog(#"AsyncFetchEngine.h: Searching similar posts among %d", [[self.fetchedResultsController fetchedObjects] count]);
Boolean found=NO;
NSPredicate *predicate=[NSPredicate predicateWithFormat:#"title == %# AND url == %# AND feed == %#", title, url, feed];
NSArray *similarPosts = [_fetchedResultsController.fetchedObjects filteredArrayUsingPredicate:predicate];
if ([similarPosts count] > 0)
{
NSLog(#"\n\n\n\t\tAsyncFetchEngine::fetchPosts> Skipping %# (%#)", title, url);
} else {
NSLog(#"\n\n\n\t\tAsyncFetchEngine::fetchPosts> Putting new post in %#", feed.name);
NSEntityDescription *postEntityDescription = [NSEntityDescription entityForName:#"Post"
inManagedObjectContext:_childManagedObjectContext];
[_childManagedObjectContext performBlock:^{
Post *initPost = (Post *)[[NSManagedObject alloc]
initWithEntity:postEntityDescription
insertIntoManagedObjectContext:_childManagedObjectContext];
initPost.title = title;
initPost.url = url;
initPost.excerpt = content;
initPost.date = date;
initPost.read = nil;
initPost.feed = feed;
NSError *error;
if (![_childManagedObjectContext save:&error])
{
NSLog(#"[createPost] Error saving context: %#", error);
}
NSLog(#"Created: %# (%#)", title, url);
//[[NSNotificationCenter defaultCenter] postNotificationName:#"NewPostAdded" object:self];
}];
}
}
So, my questions are:
When I have multiple MOCs, do I fetch from the main and write to a child?
How should I respectivelly use these above?
Thanks!
Answering my own question for the sake of eventually helping another newbie.
Check NSOperationQueue with Coredata.
There's a very good example here.

Serious issue in parsing xml and storing details using coredata

I am using google weather api to get weather information,I am using coredata to store information.I am running into troble.I am getting results on labels and UImageview to store information using coredata.My code is posted below
-(IBAction)sBarpress:(id)sender
{
NSString *urlString = [NSString stringWithFormat:#"http://www.google.co.uk/ig/api?weather=%#",sBar.text];
NSURL *url = [NSURL URLWithString:urlString];
NSLog(#"buttonpress");
WeatherXMLParser *delegate = [[WeatherXMLParser alloc] init];
NSXMLParser *locationParser = [[NSXMLParser alloc] initWithContentsOfURL:url];
[locationParser setDelegate:delegate];
[locationParser setShouldResolveExternalEntities:YES];
[locationParser parse];
/*
NSFetchRequest *request = [[NSFetchRequest alloc] init];
request.entity = [NSEntityDescription entityForName:#"Weather" inManagedObjectContext:context];
request.predicate = [NSPredicate predicateWithFormat:#"uniqueId = %#", [Data objectForKey:#"id"]];
NSError *error = nil;
NSManagedContext *returnedData = [[context executeFetchRequest:request error:&error] lastObject];
[request release];
[NSEntityDescription insertNewObjectForEntityForName:#"condition" inManagedObjectContext:context];
MODEL_OBJECT.uniqueId = [Data objectForKey:#"id"];
MODEL_OBJECT.title = [Data objectForKey:#"title"];
*/
for (WeatherCondition *condition in delegate.forecastConditions) {
NSLog(#"description is %#", condition.description);
hightemplabel.text=condition.description;
}
for (WeatherCondition *condition in delegate.forecastConditions) {
NSLog(#"description is %#", condition.icon);
NSData *mydata=[[NSData alloc]initWithContentsOfURL:[NSURL URLWithString:#"http://www.google.co.uk/ig/images/weather/partly_cloudy.gif"]];
conditionsImageView.image = [[UIImage alloc] initWithData:mydata ];
}
for (WeatherCondition *condition in delegate.forecastConditions) {
NSLog(#"description is %#", condition.icon);
NSData *mydata=[[NSData alloc]initWithContentsOfURL:[NSURL URLWithString:#"http://www.google.co.uk/ig/images/weather/thunderstorm.gif"]];
forecastimage.image = [[UIImage alloc] initWithData:mydata ];
}
for (WeatherCondition *condition in delegate.forecastConditions) {
NSLog(#"description is %#", condition.description);
humiditylabel.text=condition.description;
}
[self fetchRecords];
[locationParser release];
[delegate release];
// NSDictionary *airport = [responseString JSso ];
// displaybox.text=[airport objectForKey:#"location"];
/*
NSURL *url=[NSURL URLWithString:#"http://airportcode.riobard.com/airport/%#?fmt=json"];http://free.worldweatheronline.com/feed/weather.ashx?q=omaha%2c+ne,united+states&format=json&num_of_days=5&key=691607e82d192404111506 &format=jason
//NSURL *url = [NSURL URLWithString:urlString];
NSData *data = [response dataUsingEncoding:NSUTF8StringEncoding];
WeatherParser *locationParser = [[WeatherParser alloc] init];
[locationParser parseData:data];
label.text = locationParser.location;
urlString = [NSString stringWithFormat:#"http://free.worldweatheronline.com/feed/weather.ashx?q=%#&format=json&num_of_days=5&key=691607e82d192404111506",locationParser.location];
url = [NSURL URLWithString:urlString];
NSLog(#"area coming");
[response release];
response = [[NSString alloc] initWithContentsOfURL:url];
data = [response dataUsingEncoding:NSUTF8StringEncoding];
WeatherParser *weatherParser = [[WeatherParser alloc] init];
[weatherParser parseData:data];
[locationParser release];
[weatherParser release];
*/
}
- (void)fetchRecords {
// Define our table/entity to use
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Weather" inManagedObjectContext:managedObjectContext];
NSLog(#" entity is %#",entity);
// Setup the fetch request
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entity];
// If a predicate was passed, pass it to the query
if(predicate != nil)
{
[request setPredicate:predicate];
}
// Define how we will sort the records
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"condition" ascending:NO];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
[request setSortDescriptors:sortDescriptors];
[sortDescriptor release];
// Fetch the records and handle an error
NSError *error;
NSMutableArray *mutableFetchResults = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
if (!mutableFetchResults) {
// Handle the error.
// This is a serious error and should advise the user to restart the application
}
// Save our fetched data to an array
[self setEventArray: mutableFetchResults];
[mutableFetchResults release];
[request release];
}
You didnt really describe what the trouble is, but I can see some possible performance issues in your code ...
You are looping multiple times:
for (WeatherCondition *condition in delegate.forecastConditions) {
NSLog(#"description is %#", condition.description);
hightemplabel.text=condition.description;
}
for (WeatherCondition *condition in delegate.forecastConditions) {
NSLog(#"description is %#", condition.icon);
NSData *mydata=[[NSData alloc]initWithContentsOfURL:[NSURL URLWithString:#"http://www.google.co.uk/ig/images/weather/partly_cloudy.gif"]];
conditionsImageView.image = [[UIImage alloc] initWithData:mydata ];
}
refactor these loops into one loop through the results:
for (WeatherCondition *condition in delegate.forecastConditions) {
NSLog(#"description is %#", condition.description);
hightemplabel.text=condition.description;
NSLog(#"icon is %#", condition.icon);
NSData *mydata=[[NSData alloc]initWithContentsOfURL:[NSURL URLWithString:#"http://www.google.co.uk/ig/images/weather/partly_cloudy.gif"]];
conditionsImageView.image = [[UIImage alloc] initWithData:mydata ];
}

Printing Core Data

I'm working on a program and I have created a fetch request to grab the data that I need to print. I'm able to log information like this:
2010-10-03 16:57:10.362 lzshow7.2[2537:10b] <NSManagedObject: 0x2ca120> (entity: Song; id: 0x2afcb0 <x-coredata://CF5A85CE-BE0F-4ADC-979A-7F4214A8FB19/Song/p9> ; data: {
cueName = Freedom;
cueNo = 014;
cueNotes = nil;
songToInstrument = "<relationship fault: 0x2b1800 'songToInstrument'>";
})
How do I seperate the properties like cueName, cueNo, cueNotes out to be printed?
Here is the fetch request:
//Managed object context???
NSLog(#"setting Managed object stuff");
NSManagedObjectContext *context=[[[NSDocumentController sharedDocumentController] currentDocument] managedObjectContext];
NSLog(#"Second line of Managed object stuff");
//fetch request:
NSLog(#"Starting to fetch:");
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Song" inManagedObjectContext:context];
[request setEntity:entity];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"cueNo" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];
[sortDescriptors release];
[sortDescriptor release];
NSError *error;
NSMutableArray *mutableFetchResults = [[context executeFetchRequest:request error:&error] mutableCopy];
for (id obj in mutableFetchResults)
NSLog(#"%#", obj);
NSLog(#"finished looping");
//Error handling
if (mutableFetchResults == nil) {
// Handle the error.
}
//[self setEventsArray:mutableFetchResults];
[mutableFetchResults release];
[request release];
}
Any help would be greatly appreciated.
Thank you,
Loren
You use basically the opposite of how you stored the values in your managedObject
NSString *name = [song valueForKey:#"cueName"];
NSNumber *number = [song valueForKey:#"cueNo"];
NSString *notes = [song valueForKey:#"cueNotes"];
...
NSLog(#"%# %# %#", name, number, notes);
if you've created a custom Class of your entity you could add this method:
- (NSString *)description {
NSString *name = [song valueForKey:#"cueName"];
NSNumber *number = [song valueForKey:#"cueNo"];
NSString *notes = [song valueForKey:#"cueNotes"];
...
NSString *returnString = [NSString stringWithFormat:#"%# %# %#", name, number, notes];
return returnString;
}
With this method you can just use NSLog(#"%#", object); to get a nice formatted output

Resources