Coredata without using navigation based application - iphone

I need to use coredata in my View based Application. I created core data file. But I can't access to core data through my Viewbased application without using UITableview.
I used just UITextField and buttons only. I want to need insert records, deletion, updation and search all operations in my application.
Does anyone have some sample code without using navigation based with UITableview?

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSManagedObjectContext *context = // Your context pointer here
[fetchRequest setEntity:[NSEntityDescription entityForName:#"ObjectName" inManagedObjectContext:context]];
NSError *error;
NSArray *objects = [context executeFetchRequest:fetchRequest error:&error];
[fetchRequest release];
for (int index=0; index<[objects count]; index++) {
ObjectName *dmg = (ObjectName *)[menus objectAtIndex:index];
}
This will get you your objects out of the Core Data. You can manipulate this as you see fit as long as you commit it it will be saved in your database. It sounds like you should also search Stack Overflow (and maybe also a search engine) for information about Predicates, which allow you to filter your object graph.

Related

Xcode loading core data lag

I have 3 entities saved in core data. I am loading these in several view controllers in the app - sometimes loading data from all 3. Below is how I am loading this data and assign it to an array. Once it is in the array, then I sort, filter, count or whatever I need to do depending on the current page of the app.
if (managedObjectContext == nil)
{
managedObjectContext = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
}
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Event" inManagedObjectContext:managedObjectContext];
[request setEntity:entity];
[request setReturnsObjectsAsFaults:NO];
NSError *error = nil;
NSMutableArray *mutableFetchResults = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
if (mutableFetchResults == nil)
{
// Handle the error.
NSLog(#"mutableFetchResults == nil");
}
[self setEventsArray:mutableFetchResults];
The problems I am having are:
I don't like to have lots of duplicate code - and this is appearing on every view controller where core data is needed.
From one entity, I am saving binary data of images which is causing a lag when I load that data
So, is there a way to load from core data using conditions such as eventId = [NSString stringWithFormat:#"%#", currentEventId]
OR (and probably more suitable) have a separate class that loads the data when the app starts. And then I can access the classes arrays (of the loaded data) to use for the current page. And then just reload the data if I save, edit or delete an object.
Any help is much appreciated.
Fro your first question, you should look at MagicalRecord which brings Ruby on Rails' Active Record to CoreData. it will shorten clear your core data code.
Pay attention that if your images are not small you should store them on a separate entity with a relationship to your main entity. this should help you with the lag problem since you will load the image trough the relationship only when you will explicitly ask it to. You can see here the answer of Marcus Zarra (wrote a great book on core data). There is always an option that your images are too big for core data.
Hope it helps

Core Data. ExecuteFetchRequest with fault NSManagedObjects (not in RAM)

I need to execute fetch request. But when I do it I get not fault NSManagedObjects (each of the objects is about 5 Mb, that's why I get the memory warning). Apple provides faulting possibility for Core Data (when objects are not loaded in RAM). And I wanna my objects to use this possibility.
Here is my code
+ (NSMutableSet *)GetImagesWithPredicate:(NSPredicate *)predicate
{
NSString *entityName = kEntityName;
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];;
NSManagedObjectContext *context = appDelegate.managedObjectContext;
NSEntityDescription *entityDesctiption = [NSEntityDescription
entityForName: entityName
inManagedObjectContext:context];
// find object
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entityDesctiption];
[request setPredicate:predicate];
NSArray *objects = [context executeFetchRequest:request error:nil];
[request release];
if (objects == nil)
{
NSLog(#"there was an error");
return nil;
}
NSMutableSet *set = [NSMutableSet setWithArray:objects];
return set;
}
where predicate is (id < 500).
App crashes after
NSArray *objects = [context executeFetchRequest:request error:nil];
because all the data of objects appears in the RAM of iPhone.
It seems that default option returnsObjectsAsFaults = YES doesn't work.
The objects are probably being returned as faults; you can verify this with isFault. The issue is that Core Data automatically pre-fetches the property values for those objects and places them in the row cache (in memory). You can disable this behaviour by setting includesPropertyValues to NO on the NSFetchRequest object.
See the includesPropertyValues documentation for details of all this and the performance implications.
As an aside, you might not want to store lots of large objects in the database directly. You probably should look into using external storage if you're targeting iOS 5, or else using separate files yourself with their names/paths/ids in Core Data.
you could set the - (void)setResultType:(NSFetchRequestResultType)type for the NSFetchRequest and only get the relevant attributes for your Object with the -(void)setPropertiesToFetch:(NSArray *)values Method.
And only lazy loading the needed attributes.

Populating the Tableview from the Core Data

I have performed the save operation in core data and it is successfully done .It stores the data .I have also fetched the data into the log. This is my code for fetching data in log but I dont know how to fetch this data in TableView.
NSError *error;
DemoAppCoreDataAppDelegate *appdelegate = (DemoAppCoreDataAppDelegate *)[[UIApplication sharedApplication]delegate];
NSManagedObjectContext *context = [appdelegate managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc]init];
NSEntityDescription *entity = [NSEntityDescription entityForName: #"Employee" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSArray *fetchedobject = [context executeFetchRequest:fetchRequest error:&error];
tablearray = [[NSMutableArray alloc] initWithArray:fetchedobject copyItems:YES];
for (NSManagedObject *info in fetchedobject ) {
NSLog(# "%#",[info valueForKey:#"name"] );
}
[fetchRequest release];
I would recommend to use a NSFetchedResultsController.
Apple provides complete sample code in the NSFetchedResultsController documentation
The NSFetchedResultsController is specifically designed to work in between a tableView and Core Data. It makes everything a lot easier.
For example it will automatically insert and delete rows when you add or remove objects from the core data. For this you have to implement the NSFetchedResultsControllerDelegate protocol. The full sample code for this is in the protocol documentation
Use fetchedobject as dataSource to the tableView.
After [fetchRequest release]; , set the delegate and datasource for the tableView programatically.
The best way in this case is to inspect some working example I think. Look at the apple's example project Recipies, good one btw: easy and gives a good picture of how the things with CoreData and tableViews should be done:
http://developer.apple.com/library/ios/#samplecode/iPhoneCoreDataRecipes/Introduction/Intro.html#//apple_ref/doc/uid/DTS40008913

CoreData DetailTableView BAD_ACCESS Error

Maybe I'm not going about showing a detail for a selected row using CoreData, but I can't figure out why I'm getting a "BAD_ACCESS" error. I've googled around and can't find what I'm looking for.
Basically I use CoreData to populate the data for a Table View. It retrieves all of the title attributes for all of the entities. When the user clicks on a row, I have a Detail View that needs to show the description for that entity. I think I need to make a new NSManagedObjectContext and a new NSEntityDescription for a new NSFetchRequest in my DetailViewController and then use a NSPredicate to say "where title = [user selected title]". I get an error when I select a row. See code:
- (void)viewDidLoad
{
// Do any additional setup after loading the view from its nib.
// Get the objects from Core Data database
Caregiver_Activity_GuideAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSEntityDescription *entityDescription = [NSEntityDescription
entityForName:#"Definition"
inManagedObjectContext:context];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entityDescription];
NSPredicate *pred = [NSPredicate predicateWithFormat:#"(title = %#)", self.title];
[request setPredicate:pred];
NSError *error;
NSArray *objects = [context executeFetchRequest:request error:&error];
if (objects == nil) {
NSLog(#"There was an error!");
// Do whatever error handling is appropriate
}
for (NSManagedObject *oneObject in objects) {
[definitionDescriptionTextView setText:[oneObject valueForKey:#"desc"]];
}
[objects release];
[request release];
[super viewDidLoad];
}
I comment out that code and everything works. But when I try to debug with breakpoints, nothing catches. So I'm more confused.
I know CoreData is probably overkill for what I'm doing but this is a learning app for me.
EDIT: I didn't include that I'm using a sqlite database that is pre-populated with the entities.
You can also download my project on my github page.
Normally, with a Core Data backed Master-Detail interface, you don't fetch for the Detail view.
When you select a row in the Master tableview, you are selecting a particular managed object instance. You then pass that managed object instance to the detail view. There is no need to refetch the object that you selected in the tableview.
A good example of this would be the Contacts app. The Master tableview would be a list of Contact objects (displaying the name.) When you select a row, the Master tableview controller takes the specific Contact object associated with the selected row and then passes it to the Detail view controller which then populates the Detail view using data taking from the properties of the passed Contact object.
So, that entire code block where the error occurs is unnecessary.
However, the immediate error in this code is that you are releasing an object you didn't create. In this line:
NSArray *objects = [context executeFetchRequest:request error:&error];
... you are not creating a NSArray instance with a init, new or create method. Instead, you are merely receiving an autoreleased NSArray instance created and returned by the context NSManagedObjectContext instance. When you release an object you did not create here:
[objects release];
... you cause the crash.
Conversely, you do create a NSFetchRequest here:
NSFetchRequest *request = [[NSFetchRequest alloc] init];
... because you used init so you do have to balance that with:
[request relwase];
BTW, this type of code should not be put in viewDidLoad as the method is only called when the view is read in the first time from the nib file on disk. That is only guaranteed to happen once as the view may remain in memory when the user switches to another view. Instead, put code that needs to run each time the view appears in viewWillAppear.

Saving Core Data From Multiple TableVIews [duplicate]

This question already has answers here:
Querying Core Data with Predicates - iPhone
(4 answers)
Closed 2 years ago.
I have an app that has multiple tableviews and I want to use Core Data to capture all the data. I have two entities - freezers and items. In the first tableview I add a freezer and it saves correctly. I quit the app, re-open, and it is there. I click on the freezer (opening another tableview) and add some items and I can see them in my new sectioned tableview. I quit my app, restart it, see the freezer, click on it and there are no items.
I have my managedObjectContext in my appDelegate and reference it from there using all views, so I am not creating multiple instances. Here is the code I use to save the items to a freezer, both the managedObjectContext and my itemsArray:
Item *item = (Item *)[NSEntityDescription insertNewObjectForEntityForName:#"Item" inManagedObjectContext:[delegate managedObjectContext]];
[item setFreezer:freezerName];
[item setName:name];
[item setQuantity:quantity];
[item setSection:section];
[item setAdded:added];
[item setNotes:notes];
NSError *error = nil;
if (![[delegate managedObjectContext] save:&error]) {
NSLog(#"Freezer info didn't save. Need to handle this.");
}
[items insertObject:item atIndex:0];
Here is the code I use in the ItemViewController to retrieve the items within viewDidLoad:
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"freezer == '%#'", freezerName];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Item" inManagedObjectContext:[delegate managedObjectContext]];
NSSortDescriptor *sorts = [[NSSortDescriptor alloc] initWithKey:#"section" ascending:NO];
NSArray *sort = [[NSArray alloc] initWithObjects:sorts, nil];
[request setSortDescriptors:sort];
[request setEntity:entity];
[request setPredicate:predicate];
NSError *error = nil;
NSMutableArray *results = [[[delegate managedObjectContext] executeFetchRequest:request error:&error] mutableCopy];
if(results == nil) {
NSLog(#"Error fetching results... need to handle");
}
[self setItems:results];
NSLog(#"items count:%d", [items count]);
The item count returned is zero.
I am completely stumped and have spent several hours searching online, trying different things, and I can't figure it out. I know there are some much smarter coders out there and I hope one of you can see what the problem is.
I would try to change the predicate to
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"freezer like %#", freezerName];
Hope that helps!
Maybe the problem is that you load data in
- viewDidLoad:
method. It's called only once when your view is loaded, so when underlaying data get's changed, your view controller is not aware about it.
You can either move your loading code to
- viewWillAppear:
method or introduce notifications to spread the information that data store has changed its state and reload table views upon that event.
The best way is probably to use NSFetchedResultsController as your data source, as its always aware of its data store changes. Check docs for reference to that class.