Fetch Data from multiple Entities with no relationship between them - ios

I have to fetch data from multiple entities which are associated to different screens of an iPhone App, now the scenario is as follows, when user press a Sync button i will have to fetch data from all these entities (i have about 12 entities) and send all this data to a server via a web service, and all these entities have no relationship among them, now my question is what is the best approach to do this task, should i write 12 different fetch requests in a single method, or is there some other better approach, if any one can guide with some tutorial link, that will me most appreciated, thanx in advance.

You can use a for loop to accomplish your task like this. I've used this code to delete all entries of the Database.
NSArray *allEntities = [[[[UIApplication sharedApplication] delegate] managedObjectModel] entities];
NSError *error;
for (NSEntityDescription *entityDescription in allEntities)
{
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:entityDescription];
fetchRequest.includesPropertyValues = NO;
fetchRequest.includesSubentities = NO;
NSArray *items = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
if (error) {
NSLog(#"Error requesting items from Core Data: %#", [error localizedDescription]);
}
//Do whatever you need to do here
}

Related

How to delete a chat message which was saved using xep-0136(Message Archiving)?

I want to provide user a functionality to delete single or multiple messages at a time using long-tap/select action.
I know you want to know what I have tried so far. But the thing is I haven't found anything regarding deleting messages to implement.
Any kind of help is appreciated!
You have to delete message from xmpp core database.
So xmpp had created "XMPPMessageArchiving_Message_CoreDataObject" named core database table and using this you can delete message.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"XMPPMessageArchiving_Message_CoreDataObject" inManagedObjectContext:myAppdelObject.Obj_xmppManager.moc];
[fetchRequest setEntity:entity];
NSError *error;
NSArray *items = [mocObject executeFetchRequest:fetchRequest error:&error];
for (NSManagedObject *managedObject in items) {
[mocObject deleteObject:managedObject];
}
#Parthpatel1105's answer is right, though as #Bista says, it will not delete the messages permanently.
After performing the deletion, any deletion, either full deletion as #Parthpatel1105 does, or a single message, which would be the same but without the for loop and you'd have to find the single message to delete. You HAVE to save the storage context.
Which means, after doing:
for (NSManagedObject *managedObject in items) {
[mocObject deleteObject:managedObject];
}
You have to add a call to save,
In Swift (where I've used it):
mocObject.save()
In Objective-C, I think it would be something like:
[mocObject save:&error];

Core Data is deleting records when app crashes

I have an app that saves a lot of data in the phone. I am using the following code:
- (void)datostickets:(NSString*)cod local:(NSString*)nombre{
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSEntityDescription *ticket =[NSEntityDescription entityForName:#"History" inManagedObjectContext:context];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:ticket];
NSPredicate *pred = [NSPredicate predicateWithFormat:#"(codigo = %#)", cod];
[request setPredicate:pred];
//NSManagedObject *matches = nil;
NSError *error;
NSArray *objects = [context executeFetchRequest:request error:&error];
if ([objects count] == 0) {
NSManagedObject *nuevoticket = [NSEntityDescription insertNewObjectForEntityForName:#"History" inManagedObjectContext:context];
[nuevoticket setValue:[NSString stringWithFormat:#"%#",cod] forKey:#"codigo"];
[nuevoticket setValue:self.idloc forKey:#"actividad"];
[nuevoticket setValue:nombre forKey:#"localidad"];
NSLog(#"GRABA: %#",cod);
} else {
NSLog(#"VERIFICA");
check++;
}}
It saves fine, but the problem happens if the app crashes (I think it only happen this way, also the app only crashes when I am manipulating the data).
When the app crashes Core Data starts acting really weird, and it deletes the recent data that I saved, but somehow some of the old data is not deleted (apparently when I change of viewController Core Data makes a commit, so this old data is not deleted).
This problem is solved when I navigate trough the app windows and it starts again if the app crashes. I know the problem is pretty weird.
So, is there a way to solve this? maybe there is a commit statement or something like that.
Thanks for the help
Use [context save:&error] to commit changes.
Use context save& error .or if you using magicall records use MR_Save to persistent store and wait method other wise it is Unable to delete data from storage.

Core data and multiple entites

Having a really hard time grasping the way core data works, and I'm hoping I can get some very basic help here.
I have two entities:
Profiles<-->>Events
I have successfully figured out how to add profiles, view profiles in table view and view events for a profile in a table view via a predicate fetch.
Now, here is where I am lost. Lets say I want to update an event in the Event entity. Do I have to do a fetch with predicate to create a Profiles object before I update the Event entity? Or can I just update the Event entity and somehow tell it which Profile it is associated with via the relationship?
Here is where I have hit the log jam:
// add new event
//NSLog(#"Adding New Event");
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"Events"];
NSPredicate *predicate=[NSPredicate predicateWithFormat:#"ANY profile.profilename=[cd] %#",[self profilename]];
[fetchRequest setPredicate:predicate];
self.events = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];
//insert event info
NSManagedObject *eventInfo = [NSEntityDescription insertNewObjectForEntityForName:#"Events" inManagedObjectContext:self.managedObjectContext];
///////// THIS IS WHERE I NEED HELP
}
// save the context
NSError *error = nil;
if (![managedObjectContext save:&error]){
NSLog(#"Error! %#",error);
}
I'm about ready just to create a flat file and work with that! It's driving me nuts!
EDIT - CHANGED CODE BELOW ***********************
// add new event
//NSLog(#"Adding New Event");
Events *newEvent = (Events *)[NSEntityDescription insertNewObjectForEntityForName:#"Events" inManagedObjectContext:managedObjectContext];
newEvent.eventdesc=self.eventDescTextField.text;
NSString *wkst = eventDescTextField.text;
NSNumber *wk = [NSNumber numberWithInteger: [wkst integerValue]];
newEvent.weeksout = wk;
So now I know I need to tell the Event entity to use the current profile..how do I access the relationship?
Looking at the code you've provided, I think you have a misconception about Core Data.
It looks like you are trying to get all the events related to a profile. You don't need to create ond perform a fetch request for this. Core Data is an object graph. Which means that if you have an object in an a managed object context, you get its related objects via it's relationships, you don't need to run a fetch request.

Can not delete an entity from Core Data, using RestKit 0.20

The code below does not delete the entity. The "delete was successful" message appears on the console so the entity is found. All other operations I use succeed.
I am using RestKit 0.20.
NSManagedObjectContext *context = [RKManagedObjectStore defaultStore].mainQueueManagedObjectContext;
NSError *error = nil;
NSFetchRequest * fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity: [NSEntityDescription entityForName:#"Auction" inManagedObjectContext:context]];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"AuctionID = %d", auctionID];
[fetchRequest setPredicate:predicate];
NSArray *result = [context executeFetchRequest:fetchRequest error:&error];
if(result.count) {
Auction *block = result[0];
[context deleteObject:block];
BOOL status = [context save:&error];
if (status == NO) {
NSLog(#"delete falied for AuctionID:%d, error: %#", auctionID, error);
}
else {
[context processPendingChanges];
NSLog(#"delete was successful for AuctionID:%d", auctionID);
}
}
Why might this delete operation not succeed and what is the solution to making it work.
I found this solution :
In fact, you have to fetch datas from the persistentstore and not the current created managed context :
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:#"MyModel"];
NSSortDescriptor *descriptor = [NSSortDescriptor sortDescriptorWithKey:#"id" ascending:NO];
fetchRequest.sortDescriptors = #[descriptor];
// Setup fetched results
NSFetchedResultsController *fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:[RKManagedObjectStore defaultStore].persistentStoreManagedObjectContext
sectionNameKeyPath:nil
cacheName:nil];
// AND TO DELETE A MODEL :
[[RKManagedObjectStore defaultStore].persistentStoreManagedObjectContext deleteObject:myobject];
i am doing the same thing and have nearly same code.
In my code also, i get delete done and saved....
But, its not deleted when i am checking DB.
the problem is not with simulator... SURE bcz i am getting same problem on device also.
there is something called child context, it might be the cause...Check these links http://restkit.org/api/0.20.0-dev/Classes/RKManagedObjectRequestOperation.html#//api/name/managedObjectContext
RestKit 0.20 — What is the preferred way to create a new NSManagedObject?
. If you found solution pls share here
#Sumitiscreative I ran into the same issue today. What if found was that normally using Core Data you have to use
[NSManagedObject save:]
for it to store the changes. I dug through Restkit a bit and found this
[[RKManagedObjectStore defaultStore].persistentStoreManagedObjectContext deleteObject:(NSManagedObject *)];
[[RKManagedObjectStore defaultStore].persistentStoreManagedObjectContext saveToPersistantStore:(NSError *)];
Calling this after the above delete method is working to remove the object out of the DB.
**Edit - Also I would have just made this a comment but i don't have the option
#Lance
Hey, pls update your restkit with the latest version.
As now, this works in the latest version , if your server related configuration is correct. and if you get success codes for your delete request from server. Then, restkit automatically deletes the data.
If you need to delete any data externally then, you can use persistentStoreManagedObjectContext and after deleting, save it.
Also, if you want to check at your end that whether its correctly deleting via restkit or not. what you can do is ...
make delete request, after success
check with same id, if item exists. (just for help)

efficiently display 100,000 items using Core Data

I am using a NSFetchResultsController to display 100,000 + records in a UITableView. This works but it is SLOW, especially on an iPad 1. It can take 7 seconds to load which is torture for my users.
I'd also like to be able to use sections but this adds at least another 3 seconds onto the laod time.
Here is my NSFetchResultsController:
- (NSFetchedResultsController *)fetchedResultsController {
if (self.clientsController != nil) {
return self.clientsController;
}
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Client" inManagedObjectContext:self.managedObjectContext];
[request setEntity:entity];
[request setPredicate:[NSPredicate predicateWithFormat:#"ManufacturerID==%#", self.manufacturerID]];
[request setFetchBatchSize:25];
NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:#"UDF1" ascending:YES];
NSSortDescriptor *sort2= [[NSSortDescriptor alloc] initWithKey:#"Name" ascending:YES];
[request setSortDescriptors:[NSArray arrayWithObjects:sort, sort2,nil]];
NSArray *propertiesToFetch = [[NSArray alloc] initWithObjects:#"Name", #"ManufacturerID",#"CustomerNumber",#"City", #"StateProvince",#"PostalCode",#"UDF1",#"UDF2", nil];
[request setPropertiesToFetch:propertiesToFetch];
self.clientsController =
[[NSFetchedResultsController alloc] initWithFetchRequest:request
managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil
cacheName:nil];
return self.clientsController;
}
I have an index on ManufacturerID which is used in my NSPredicate. This seems like a pretty basic NSFetchRequest - anything I can do to speed this up? Or have I just hit a limitation? I must be missing something.
First: you can use the NSFetchedResultsController's cache to speed up display after the first fetch. This should quickly go down to a fraction of a second.
Second: you can try to display the only the first screenful and then fetch the rest in the background. I do this in the following way:
When the view appears, check if you have the first page cache.
If not, I fetch the first page. You can accomplish this by setting the fetch request's fetchLimit.
In case you are using sections, do two quick fetches to determine the first section headers and records.
Populate a second fetched results controller with your long fetch in a background thread.
You can either create a child context and use performBlock: or
use dispatch_async().
Assign the second FRC to the table view and call reloadData.
This worked quite well in one of my recent projects with > 200K records.
I know the answer #Mundi provided is accepted, but I've tried implementing it and ran into problems. Specifically the objects created by the second FRC will be based on the other thread's ManagedObjectContext. Since these objects are not thread safe and belong to their own MOC on the other thread, the solution I found was to fault the objects as they are being loaded. So in cellForRowAtIndexPath I added this line:
NSManagedObject *object = [self.fetchedResultsController objectAtIndexPath:indexPath];
object = (TapCellar *)[self.managedObjectContext existingObjectWithID:[object objectID] error:nil];
Then you have an object for the correct thread you are in. One further caveat is that the changes you make to the objects won't be reflected in the background MOC so you'll have to reconcile them. What I did was make the background MOC a private queue MOC and the foreground one is a child of it like this:
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
_privateManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[_privateManagedObjectContext setPersistentStoreCoordinator:coordinator];
_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[_managedObjectContext setParentContext:_privateManagedObjectContext];
}
Now when I make changes in the main thread, I can reconcile them easily by doing this:
if ([self.managedObjectContext hasChanges]) {
[self.managedObjectContext performBlockAndWait:^{
NSError *error = nil;
ZAssert([self.managedObjectContext save:&error], #"Error saving MOC: %#\n%#",
[error localizedDescription], [error userInfo]);
}];
}
I wait for it's return since I'm going to reload the table data at this point, but you can choose not to wait if you'd like. The process is pretty quick even for 30K+ records since usually only one or two are changed.
Hope this helps those who are stuck with this!

Resources