iOS NSManagedObject Data <fault> while deleting - ios

I am having some difficulties in deleting an entry from Core Data.
It works but the NSManagedObject data has no values (fault), and so sometimes the wrong entry will be deleted.
In my deleteWholeDatabase method the objects are filled with values.
And in the deleteEntryFromDatabase method are no values. But why?
Here are my methods:
-(NSArray*)databaseRequest{
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:currentEntity inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
[fetchRequest setReturnsObjectsAsFaults:NO];
NSError *error;
NSArray *items = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
return items;
}
-(void)deleteWholeDatabase{
for (NSManagedObject *objectToDelete in [self databaseRequest]) {
[managedObjectContext deleteObject:objectToDelete];
NSLog(#"%# object deleted",objectToDelete);
}
[self saveContext];
NSLog(#"All entries deleted!");
}
-(void)deleteEntryFromDatabase:(NSManagedObjectContext*)context forEntry:(NSIndexPath*)indexPath{
NSManagedObject *objectToDelete=[[self databaseRequest] objectAtIndex:indexPath.row];
[managedObjectContext deleteObject:[managedObjectContext objectWithID:[objectToDelete objectID]]];
[self saveContext];
NSLog(#"%# deleted!",[managedObjectContext objectWithID:[objectToDelete objectID]]);
}

The wrong entry is being deleted because each request return the itens in a different order. Try deleting the intens by comparing their memory adress

Instead of keeping a calling [self databaseRequest] everywhere, I would keep a local copy of NSManagedObjectID's as an array.
- (void)init {
self.entities = [self databaseRequest];
}
-(NSArray*)databaseRequest{
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:currentEntity inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
[fetchRequest setReturnsObjectsAsFaults:NO];
NSError *error;
NSArray *items = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
NSMutableArray *itemIDs = [[NSMutableArray alloc] initWithCapacity:[items count]];
for (NSManangedObject *item in items) {
[itemIDs addObject:[item objectID]];
}
return items;
}
Then everywhere where you call [self databaseRequest], you will get an have the correct NSManagedObjectID. Then you just need to get the correct entity from the ID.

Related

Core Data: Fetch all children in a 1 to many relationship

I have 1-many relationship and I am successfully putting data into it. The problem is that I am not able to fetch it out via the relationship attribute.
My ADD Code:
NSManagedObjectContext *context = [[CBICoreDataController sharedInstance] masterManagedObjectContext];
NSManagedObject *orders = [NSEntityDescription
insertNewObjectForEntityForName:#"UnsyncedOrders"
inManagedObjectContext:context];
[orders setValue:[dictionary valueForKey:#"specialInstructions"] forKey:#"specialInstructions"];
[orders setValue:[dictionary valueForKey:#"poNumber"] forKey:#"poNumber"];
[orders setValue:[dictionary valueForKey:#"specialInstructions"] forKey:#"specialInstructions"];
[orders setValue:[dictionary valueForKey:#"deliveryDate"] forKey:#"deliveryDate"];
[orders setValue:[dictionary valueForKey:#"account"] forKey:#"account"];
NSMutableSet *muteSet=[orders mutableSetValueForKey:#"items"];
for (NSDictionary *dict in [dictionary valueForKey:#"items"]) {
NSManagedObject *items = [NSEntityDescription
insertNewObjectForEntityForName:#"UnsyncedOrderItems"
inManagedObjectContext:context];
[items setValue:[dict valueForKey:#"arraykey"] forKey:#"arrayKey"];
//Other Sets Here
[muteSet addObject:items];
}
[orders setValue:muteSet forKey:#"items"];
NSError *error;
if (![context save:&error]) {
NSLog(#"Error saving in writeToMenuCostingDetailsTable: %#", [error localizedDescription]);
}
What I have for the fetch now but it does not work:
NSFetchRequest * fetchRequest = [[NSFetchRequest alloc] init];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"arrayKey" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
NSEntityDescription *parent = [NSEntityDescription entityForName:#"UnsyncedOrders"
inManagedObjectContext:context];
NSEntityDescription *child = [NSEntityDescription entityForName:#"UnsyncedOrderItems"
inManagedObjectContext:context];
[fetchRequest setEntity:child];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"orders == %#", parent];
[fetchRequest setPredicate:predicate];
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:context sectionNameKeyPath:nil cacheName:nil];
NSError *error;
[aFetchedResultsController performFetch:&error];
NSArray *fetchedObjects = [aFetchedResultsController fetchedObjects];
Your orders relationship relates to a specific instance of UnsyncedOrders. However when you try to perform a fetch, you do this:
NSEntityDescription *parent = [NSEntityDescription entityForName:#"UnsyncedOrders"
inManagedObjectContext:context];
[...]
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"orders == %#", parent];
[fetchRequest setPredicate:predicate];
You're trying to fetch instances where the orders relationship points to the UnsyncedOrders entity itself, not those that relate to a specific instance of UnsyncedOrders. That's always going to fail. In fact there's a good chance that if you were checking the result of performFetch: that it's returning NO and providing you with some sort of error describing the problem.
If you want to fetch the UnsyncedOrderItems that relate to a specific instance of UnsyncedOrders, you need to use a predicate that refers to a specific instance. However, if you already have that instance, you don't need to fetch-- just ask the UnsyncedOrders instance for the value of its items relationship.
This is the solution that I ended up using:
NSManagedObjectContext *context = [[CBICoreDataController sharedInstance] masterManagedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"UnsyncedOrders"
inManagedObjectContext:context];
NSError *error = nil;
[fetchRequest setEntity:entity];
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
for (UnsyncedOrders *info in fetchedObjects) {
[mutableArray addObject:info.items];
}

How to update fetched managed objects?

I'm having troubles in updating a specific record in my core data. What happens in my code is it does change the value but when I rerun the app it goes back to its original value. Why that happens?
NSManagedObjectContext *context = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Wish" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
// Specify criteria for filtering which objects to fetch
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"itemWish = %#", self.wishItemStr];
[fetchRequest setPredicate:predicate];
NSError *error = nil;
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
[fetchedObjects setValue:#"YES" forKeyPath:#"isAchieved"];
if (fetchedObjects == nil) {
NSLog(#"no fetched objects!");
}
You need to save the context.
[managedObjectContext save:&error];
I suggest you to read these very good tutorials and articles on objc.io.

Fetching data in coredata

-(void)getRecords
{
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"CustomerOrder"
inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
NSError* error;
NSArray *fetchedRecords = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
if (fetchedRecords)
{
if (fetchedRecords.count == 0) //create new Entity
{
NSLog(#"Balaiah babu");
}
else
{
int count =0;
for (int i=0; i<fetchedRecords.count; i++) {
CustomerOrder * record = [fetchedRecords objectAtIndex:i];
NSLog(#"%#,%#,%#,%#,%#,%#,%#,%#,%#,%#,%#",record.customer_id,record.order_id,record.outletLatitude,record.outletLongitude,record.trigger_days,record.trigger_end_date,record.trigger_from_time,record.trigger_no_days,record.trigger_radius,record.trigger_start_date,record.trigger_to_time);
NSLog(#"%d",count++);
}
}
}
}
here fetched Records array is showing nil.But it is going through loop and printing the values of the log.I don't know how it is happening.
In .h File
#property (strong, nonatomic) NSManagedObjectContext *managedObjectContext;
In .m File
Fetch entity "Info"
NSEntityDescription *entity =
[NSEntityDescription entityForName:#"Info"
inManagedObjectContext:managedObjectContext];
fetch entity request
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entity];
Fetch the records and handle an error
NSMutableArray *mutableFetchResults =
[[managedObjectContext executeFetchRequest:request
error:&error] mutableCopy];
if (!mutableFetchResults)
{
Nslog(#"nil");
}
Save our fetched data to an array
NSLog(#"get_Result==%#",[mutableFetchResults valueForKey:#"fname"]);

Why coredata is returning null array while I am inserting values in table

I have two methods,
In first method, I do save values in Core Data, while in other, I simply fetch them.
After inserting, when I fetch data in same method, it shows value, but when I try to fetch in other method if returns me null.
My saving Method is
-(void) saveloginData:(NSString *)facebookTok username:(NSString *)userName password:(NSString*)password flag:(NSString *)flag {
NSError *error;
NSManagedObjectContext *context = [self managedObjectContext];
NSFetchRequest * fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:[NSEntityDescription entityForName:#"SignIn" inManagedObjectContext:context]];
[fetchRequest setIncludesPropertyValues:NO]; //only fetch the managedObjectID
NSString *facebookTokenData = facebookTok;
NSString *usernameData = userName;
NSString *passwordData = password;
NSString *flagData = flag;
NSLog(#"Facebook Token%#\nUsername%#\npassword%#\nflat%#\n",facebookTokenData,usernameData,passwordData,flagData);
SignIn *signIn = [NSEntityDescription
insertNewObjectForEntityForName:#"SignIn"
inManagedObjectContext:context];
signIn.facebookToken = facebookTokenData;
signIn.username = usernameData;
signIn.password = passwordData;
signIn.flag = flagData;
NSEntityDescription *entity = [NSEntityDescription entityForName:#"SignIn"
inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSArray *fetchedArray = [context executeFetchRequest:fetchRequest error:&error];
for (SignIn *info in fetchedArray) {
\\ THis executes and shows values, proves that value are inserted.
NSLog(#"Name ~~~~ : %#", info.username);
NSLog(#"Password ~~~~~~~~ :%#", info.password);
NSLog(#"FLAG ~~~~~~~~~~~ %#",info.flag);
NSLog(#"Facebook Token %#", info.facebookToken);
}
}
My retrieve Method is
-(NSArray*) getLoginData {
NSError *error;
NSManagedObjectContext *context = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"SignIn"
inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSArray *fetchedData = [[NSArray alloc] init];
fetchedData = [context executeFetchRequest:fetchRequest error:&error];
NSLog(#"The count of Array %d", [fetchedData count]); \\ HERE COUNT IS ZERO, WHY?
for (SignIn *info in fetchedData) {
NSLog(#" FF Name ~~~~ : %#", info.username);
NSLog(#"Password ~~~~~~~~ :%#", info.password);
NSLog(#"FLAG ~~~~~~~~~~~ %#",info.flag);
NSLog(#"Facebook Token %#", info.facebookToken);
}
return fetchedData;
}
Please guide that where I am doing mistake.
Your problem is that you need to save conext to get the entity it later.
NSManagedObjectContext save: Attempts to commit unsaved changes to registered objects to their persistent store.
- (BOOL)save:(NSError **)error
Parameters: error: A pointer to an NSError object. You do not need to create an NSError object. The save operation aborts after the first failure if you pass NULL.
Return Value YES if the save succeeds, otherwise NO.
So you need to save context after you modify your object:
signIn.facebookToken = facebookTokenData;
signIn.username = usernameData;
signIn.password = passwordData;
signIn.flag = flagData;
[context save:NULL]; // NULL if you don't need to handle error

ios core data - copy entity records to another entity

I have 2 entity, Units and BUnits, the Units entity have a data that will be replaced many time, and the BUnits will be the backup of the Units entity before clearing it's data.
So, I've created a NSManagedObjectContext instance, then I've retrive an instance for each entity by using
NSManagedObjectContext *context = [mainDelegate managedObjectContext];
NSEntityDescription *unitsEntity = [NSEntityDescription entityForName:#"Units" inManagedObjectContext:context];
NSEntityDescription *bUnitsEntity = [NSEntityDescription entityForName:#"BUnits" inManagedObjectContext:context];
but i've didn't managed to copy the Units entity records to the BUnits entity, other than make a loop for each records, but i believe that there is a better solution.
What do you think about this, is there a better solution?
UPDATE:
The solution i've used in case anyone could use it is in my answer, I think there is a better way to do this, i will keep checking for it and i will update the question if i found anything.
Here is what i've used, using looping for each record:
- (void) copyEntities:(NSString *)sourceEntity And:(NSString *)destinationEntity {
NSManagedObjectContext *context = [mainDelegate managedObjectContext];
NSEntityDescription *Units = [NSEntityDescription entityForName:sourceEntity inManagedObjectContext:context];
NSEntityDescription *BUnits = [NSEntityDescription entityForName:destinationEntity inManagedObjectContext:context];
NSFetchRequest *dataRequest = [[NSFetchRequest alloc] init];
[dataRequest setEntity:Units];
NSError *error = nil;
NSArray *dataArray = [context executeFetchRequest:dataRequest error:&error];
for (UnitsClass *unit in dataArray) {
UnitsClass *savedUnits;
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:BUnits];
NSPredicate *pred = [NSPredicate predicateWithFormat:#"(code = %#)", unit.code];
NSPredicate *pred1 = [NSPredicate predicateWithFormat:#"(code2 = %#)", unit.code2];
NSPredicate *compoundPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:[NSArray arrayWithObjects:pred, pred1, nil]];
[request setPredicate:compoundPredicate];
NSError *error = nil;
NSArray *objects = [context executeFetchRequest:request error:&error];
//this if to indicate if we inserting to the BUnits or updating it.
if ([objects count] > 0) {
//Found the record, update The info
savedUnits = [objects objectAtIndex:0];
} else {
savedUnits = [NSEntityDescription insertNewObjectForEntityForName:destinationEntity inManagedObjectContext:context];
}
savedUnits.code = unit.code;
/*Add your updated info*/
NSError *errors;
if (![context save:&errors]) {
NSLog(#"Whoops, couldn't save: %#", [errors localizedDescription]);
}
}
NSLog(#"BUnits count = %d",[context countForFetchRequest:[NSFetchRequest fetchRequestWithEntityName:destinationEntity] error:&error]);
}
Based on the given information, there is no better way than looping each unit object and creating the backup object.

Resources