UISlider core data programing - cocoa-touch

Im working on a simple "point based" app.
under settings the user set´s the number of points needed to get a "goodie" using a slider.
-(IBAction) sliderChanged: (id)sender {
UISlider *slider = (UISlider *) sender;
int progressAsInt =(int)(slider.value +0.5);
NSString *newText = [[NSString alloc] initWithFormat:#"%d",progressAsInt];
sliderLabel.text = newText;
[newText release];
this works fine, but how so i store the slider value in my core data model, and how do make my slider show the stored value when view loads.
hope u can help me out :-D
Hey gerry3 i found my error. i never set my toD-object in my settingsViewController, with:
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:[NSEntityDescription
entityForName:#"ToDo" inManagedObjectContext:_context]];
NSError *error = nil;
NSArray *array = [_context executeFetchRequest:request error:&error];
if (array == nil)
{
// Deal with error...
}
if(array.count > 0){
toDo = [array objectAtIndex:0];
} else { // no one to fetch - generate one
toDo = [NSEntityDescription
insertNewObjectForEntityForName:#"ToDo"
inManagedObjectContext:_context];
[toDo retain];
your code works like a charm .....
Thanks
Skov

The key here is that Core Data stores numeric attributes (e.g. integers, floats, etc) as NSNumber objects.
Say that your entity is called Record and it has a integer attribute called 'progress'.
If you create a managed object instance of Record named 'record', then you can set its progress like this:
[record setValue:[NSNumber numberWithInteger:progressAsInt] forKey:#"progress"];
When you want to update your view with the value from your model (usually in viewWillAppear:), you can get its progress like this:
NSNumber *progressNumber = [record valueForKey:#"progress"];
slider.value = [progressNumber floatValue];
Alternatively, if you generate the class files for the Record entity, you can just do:
record.progress = [NSNumber numberWithInteger:progressAsInt];
and:
slider.value = [record.progress floatValue];

Related

Core Data TableView - Multiple Selection During Edit Mode

I have two TableViews using Core Data. I have an ItemTableview with multiple rows of Item listed by the user, and it allows multiple selection during edit mode. During edit mode, it allows user to delete selected items, or delete all of the items at once. I want the items that's been deleted to be added to a TrashTableView.
Here's what I have so far:
- (IBAction)deleteAction:(id)sender
{
NSManagedObjectContext *context = [self managedObjectContext];
NSArray *selectedRows = [self.tableView indexPathsForSelectedRows];
BOOL noItemsAreSelected = selectedRows.count == 0;
BOOL deleteSpecificRows = selectedRows.count > 0;
if (noItemsAreSelected) {
// Delete all objects from the Core Data.
NSFetchRequest *allItems = [[NSFetchRequest alloc] init];
[allItems setEntity:[NSEntityDescription entityForName:#"Item" inManagedObjectContext:context]];
[allItems setIncludesPropertyValues:NO];
NSError *error = nil;
NSArray *items = [context executeFetchRequest:allItems error:&error];
for (NSManagedObject *object in items) {
[context deleteObject:object];
}
// Add to Trash
for (NSManagedObject *trashObject in items) {
Item *selectedItems = trashObject; <-- #warning -Incompatible pointer types initializing "Items" with an expression of type "NSManagedObject"-
Trash *newTrash = [NSEntityDescription insertNewObjectForEntityForName:#"Trash" inManagedObjectContext:context];
newTrash.trashname = selectedItems.itemname;
newTrash.created = [NSDate date];
// Save the context
NSError *saveError = nil;
if (![context save:&saveError]) {
NSLog(#"Save Failed! %# %#", saveError, [saveError localizedDescription]);
}
}
// Delete from the Array
[_item removeAllObjects];
// Tell the tableView that we deleted the objects.
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tableView setEditing:NO animated:YES];
}
else if (deleteSpecificRows) {
NSMutableIndexSet *indicesOfItemsToDelete = [NSMutableIndexSet new];
for (NSIndexPath *selectionIndex in selectedRows)
{
[indicesOfItemsToDelete addIndex:selectionIndex.row];
}
// Delete from the Array
[_item removeObjectsAtIndexes:indicesOfItemsToDelete];
// Tell the tableView that we deleted the objects
[self.tableView deleteRowsAtIndexPaths:selectedRows withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tableView setEditing:NO animated:YES];
}
}
When if (noItemsAreSelected) is called, all of the items are deleted and they all get added to the TrashTableView, but only a first row from the ItemTableView gives the string. So in the TrashTableView, first row has a text but the rest of the rows are just blank cells without any text.
In the debugger, blank cells have NSString trashname = nil; but NSDate created = "2015-01-22 03:41:30 +0000"; has a date.
For else if (deleteSpecificRows) I have no idea how to do it in Core Data....
I've spent quiet a lot of time trying to figure this out, so any help would be greatly appreciated. Thanks!
You are doing things in the wrong order: you currently delete all the items from the context, then iterate through the items, creating the corresponding trash items and saving the context each time. This works OK for the first item. But after the first item, the context has already been saved, so the delete operation (for ALL the items) will have happened, which nils out all their properties. Hence your null values.
I would restructure it as follows:
if (noItemsAreSelected) {
NSFetchRequest *allItems = [[NSFetchRequest alloc] init];
[allItems setEntity:[NSEntityDescription entityForName:#"Item" inManagedObjectContext:context]];
[allItems setIncludesPropertyValues:NO];
NSError *error = nil;
NSArray *items = [context executeFetchRequest:allItems error:&error];
for (Item *trashObject in items) {
// Add to Trash
Trash *newTrash = [NSEntityDescription insertNewObjectForEntityForName:#"Trash" inManagedObjectContext:context];
newTrash.trashname = trashObject.itemname;
newTrash.created = [NSDate date];
// Delete
[context deleteObject:trashObject];
}
// Save the context
NSError *saveError = nil;
if (![context save:&saveError]) {
NSLog(#"Save Failed! %# %#", saveError, [saveError localizedDescription]);
}
Note that changing the cast in the for(Item *trashObject ...) should avoid the compiler warning.
EDIT
For the deleteSpecificRows case, you can use similar code, but using your _item (I assume that is a mutable array which is the datasource for your tableView):
else if (deleteSpecificRows) {
NSMutableIndexSet *indicesOfItemsToDelete = [NSMutableIndexSet new];
for (NSIndexPath *selectionIndex in selectedRows)
{
// First, get the trash object...
Item *trashObject = [_item objectAtIndex:selectionIndex.row];
// Add to Trash
Trash *newTrash = [NSEntityDescription insertNewObjectForEntityForName:#"Trash" inManagedObjectContext:context];
newTrash.trashname = trashObject.itemname;
newTrash.created = [NSDate date];
// and delete the object from the context
[context deleteObject:trashObject];
// and update the list of items to delete
[indicesOfItemsToDelete addIndex:selectionIndex.row];
}
// Delete from the Array
[_item removeObjectsAtIndexes:indicesOfItemsToDelete];
// Tell the tableView that we deleted the objects
[self.tableView deleteRowsAtIndexPaths:selectedRows withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tableView setEditing:NO animated:YES];
}
Note that this is untested, so might need tidying up....
Longer term, you might want to consider a) using a NSFetchedResultsController to act as your datasource for your tableView, and b) rather than creating separate entities for the trash, add flag to the existing entities (inTrash?) and just changing that to true. Your tableView would then have to show only items with inTrash = false.

How to sort distance in sectional table view?

I'm making app with section tableview.The section header display district through keyArray. To row of table view, it will display all information including of name, address and distance. I can make it by below code.
Now, I'm going to sort ascending distance in tableview.
How can I sort it in 'cellForRowAtIndexPath' method?
My second thought is create NSArray at the outside of cellForRowAtIndexPath method. One is to load plist data and calculate distance. And then, sort it through NSSortDescriptor. If I go to this method, I am not sure how to populate it in section tableview correctly?
Can someone give me some idea or suggestion?
In key array, I use below code to create it in ViewDidLoad and put it into section header.
//location info draw from plist
NSArray*tempArray=[[NSArray alloc]init];
tempArray=[dataDictionary allKeys];
self.keyArray=[tempArray mutableCopy];
In cellForRowAtIndexPath, it calculate distance between target location and user location. And then display all information in table view row.
NSString*sectionHeader=[keyArray objectAtIndex:indexPath.section];
NSArray*sectionHeaderArray=[dataDictionary objectForKey:sectionHeader];
NSDictionary*targetLat=[sectionHeaderArray objectAtIndex:indexPath.row];
NSDictionary*targetLong=[sectionHeaderArray objectAtIndex:indexPath.row];
//location info draw from plist
CLLocation *targetLocation = [[CLLocation alloc] initWithLatitude:[[targetLat objectForKey:#"latitude"] floatValue] longitude:[[targetLong objectForKey:#"longitude"] floatValue]];
double distance = [self.myLocation distanceFromLocation:targetLocation]/1000;
UITableViewCell*cell=[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell==nil) {
cell=[[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitlereuseIdentifier:CellIdentifier] autorelease];
}
UILabel*nameLabel=(UILabel*)[cell viewWithTag:100];
UILabel*addLabel=(UILabel*)[cell viewWithTag:101];
UILabel*latLabel1=(UILabel*)[cell viewWithTag:102];
UILabel*longLabel1=(UILabel*)[cell viewWithTag:103];
UILabel*disLabel=(UILabel*)[cell viewWithTag:106];
NSDictionary*name=[sectionHeaderArray objectAtIndex:indexPath.row];
NSDictionary*address=[sectionHeaderArray objectAtIndex:indexPath.row];
nameLabel.text=[name objectForKey:#"name"];
addrLabel.text=[address objectForKey:#"address"];
latLabel1.text=[NSString stringWithFormat:#"%f",self.myLocation.coordinate.latitude];
longLabel1.text=[NSString stringWithFormat:#"%f",self.myLocation.coordinate.longitude];
disLabel.text=[NSString stringWithFormat:#"%0.2f km",distance];
return cell;
}
I jumped to conclusions and posted an answer that was flawed. I see now that you have a multitude of issues in your process.
You assign the same object, [sectionHeaderArray objectAtIndex:indexPath.row], to several different variables and are expecting different results from each. To start with, I would make the following changes to your existing code:
NSString*sectionHeader=[keyArray objectAtIndex:indexPath.section];
NSArray *locationsForSection = [self.dataDictionary objectForKey:sectionHeader];
NSDictionary *thisLocationInfo = [locationsForSection objectAtIndex:indexPath.row];
float thisLat = [[thisLocationInfo objectForKey:#"latitude"] floatValue];
float thisLong = [[thisLocationInfo objectForKey:#"longitude"] floatValue];
//location info draw from plist
CLLocation *targetLocation = [[CLLocation alloc] initWithLatitude:thisLat longitude:thisLong];
double distance = [self.myLocation distanceFromLocation:targetLocation]/1000;
UITableViewCell*cell=[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell==nil) {
cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitlereuseIdentifier:CellIdentifier];
}
UILabel*nameLabel=(UILabel*)[cell viewWithTag:100];
UILabel*addLabel=(UILabel*)[cell viewWithTag:101];
UILabel*latLabel1=(UILabel*)[cell viewWithTag:102];
UILabel*longLabel1=(UILabel*)[cell viewWithTag:103];
UILabel*disLabel=(UILabel*)[cell viewWithTag:106];
NSDictionary*name=[sectionHeaderArray objectAtIndex:indexPath.row];
NSDictionary*address=[sectionHeaderArray objectAtIndex:indexPath.row];
latLabel1.text=[NSString stringWithFormat:#"%f",thisLat];
longLabel1.text=[NSString stringWithFormat:#"%f",thisLong];
disLabel.text=[NSString stringWithFormat:#"%0.2f km",distance];
return cell;
}
For your sorting issue, I would say to go back to your dataDictionary. Iterate through each of the sectionHeader arrays. Replace each array with a copy that is sorted by the distance from myLocation. You could add the key, distance, to each dictionary there and take that out of the cellForRowAtIndexPath method entirely.
-(NSDictionary *)dataDictionary
{
if (_dataDictionary) {
return _dataDictionary;
}
NSMutableDictionary *resultDictionary = [[NSMutableDictionary alloc] init];
for (NSString *sectionHead in self.keyArray) {
NSMutableArray *sectionArrayWithDistances = [[NSMutableArray alloc] init];
NSArray *thisSectionArray = [sourceDictionary objectForKey:sectionHead];
for (NSDictionary *theLocationDict in thisSectionArray) {
// Calculate the distance
float thisLat = [[theLocationDict objectForKey:#"latitude"] floatValue];
float thisLong = [[theLocationDict objectForKey:#"longitude"] floatValue];
CLLocation *targetLocation = [[CLLocation alloc] initWithLatitude:thisLat longitude:thisLong];
double distance = [self.myLocation distanceFromLocation:targetLocation]/1000;
// Insert modified dictionary into the resulting section array
NSMutableDictionary *thisLocationWithDistance = [NSMutableDictionary dictionaryWithDictionary:theLocationDict];
[thisLocationWithDistance insertObject:[NSNumber numberWithDouble:distance] ForKey:#"distance"];
[sectionArrayWithDistances addObject:[NSDictionary dictionaryWithDictionary:thisLocationWithDistance]];
}
// Sort the resulting array for this section and insert in dataDict
NSSortDescriptor *sortByDistance = [[NSSortDescriptor alloc] initWithKey:#"distance" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObjects:sortByDistance, nil];
[sectionArrayWithDistances sortWithDescriptors:sortDescriptors];
[resultDictionary insertObject:[NSArray arrayWithArray:sectionArrayWithDistances] forKey:sectionHead];
}
// Set result and return
self.dataDictionary = [NSDictionary dictionaryWithDictionary:resultDictionary];
return _dataDictionary;
}
Total Air Code and turned out to be more than I bargained for. Possible errors in syntax and what not but this is the basic idea as I see it for your purposes.

Core Data Edit/Save Attributes in an Entity

I am struggling with the editing/saving in Core Data and need some help in this. I am using NSFetchedResultsController and have an entity named Golfer with attributes- first_name, last_name, email_id and others in Core Data. So, I know how to add and remove golfers from the database.
I am working on one view controller called ViewManager (kinda base view for all my classes) and it has 2-3 Custom UIViews inside it. I animate them in and out whenever I need them.
I add a golfer to the tableview, then on didSelectRow tableview method, I present my edit View inside the same ViewManager controller and try to update the textfields in the edit view using the following code, but it's updating at random indexes in the tableview and not working for me. Any help would be greatly appreciated.
- (IBAction)saveEditGolfersView:(id)sender
{
AppDelegate * applicationDelegate = (AppDelegate *) [[UIApplication sharedApplication] delegate];
NSManagedObjectContext * context = [applicationDelegate managedObjectContext];
// Retrieve the entity from the local store -- much like a table in a database
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Golfer" inManagedObjectContext:context];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entity];
// Set the sorting -- mandatory, even if you're fetching a single record/object
NSSortDescriptor *sortDescriptor1 = [[NSSortDescriptor alloc] initWithKey:#"first_name" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor1,nil];
[request setSortDescriptors:sortDescriptors];
[sortDescriptors release]; sortDescriptors = nil;
[sortDescriptor1 release]; sortDescriptor1 = nil;
NSError * error;
NSArray * objects = [context executeFetchRequest:request error:&error];
for(int i = 0; i<[objects count]; i++)
{
Golfer * golfguy = [objects objectAtIndex:i];
golfguy.first_name = mEditFirstName.text;
golfguy.middle_name = mEditMiddleName.text;
golfguy.last_name = mEditLastName.text;
golfguy.email_id = mEditEmailField.text;
golfguy.contactNumber = mEditContactNum.text;
golfguy.picture = mEditPictureView.image;
NSLog(#"name-%#", golfguy.first_name);
}
[request release]; request = nil;
error = nil;
[context save:&error];
[UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseOut
animations:^ {
mEditGolfersView.frame = CGRectMake(-480, mEditGolfersView.frame.origin.y, mEditGolfersView.frame.size.width, mEditGolfersView.frame.size.height);
}
completion:^(BOOL finished) {
mEditGolfersView.hidden = YES;
}];
}
If I have read this code correct, then a call to -(IBAction)saveEditGolfersView:(id)sender will set all the Golfers with the exact properties, which I expect is not what you want.
I am not quite sure what the problem is, but I hypothesize that you need an NSPredicate to go along with your NSFetchRequest in order to change the correct Golfer(s).
Maybe I missed something, but this code says to me "hey, I'm going to load all of the Golfer in the database, order them by their first name, and then set all of their properties to the exact same text fields on this page". Just sounds like bad news...
To edit just one golfer, be sure to store the golfer you are editing in a property some where. Since you keep the managedObjectContext stored on the applicationDelegate, it will stay alive and thus keep your core data objects alive. That would avoid the expensive fetch that you are doing in the save view. If, however, you do not want to keep a reference to the golfer object, each NSManagedObject has an objectId, which is the identifier used by core data. You could use the objectId in a fetch predicate like so:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"objectId == %#", self.editingGolferObjectId];
[request setPredicate:predicate];
I would choose to keep reference to the object in your case, rather than the objectId

Adding Objects from an Array into Core Data

So, for the past two days or so I've been struggling with something that should honestly be a simple task. Here's a little introduction on what I'm trying to achieve.
What I'm doing is utilising a web service of my own, sending a request and parsing the returned JSON with SBJSON. What I know want to accomplish with this parsed JSON is to insert it into Core Data.
I have built a object model already which looks like the following:
#import <CoreData/CoreData.h>
#interface Event : NSManagedObject
{
}
#property (nonatomic, retain) NSString * summary;
#property (nonatomic, retain) NSString * content;
#property (nonatomic, retain) NSDate * updated;
#property (nonatomic, retain) NSString * title;
#property (nonatomic, retain) NSDate * created;
#property (nonatomic, retain) NSString * ID;
#end
These are all built in regards to what is being parsed, I think I may have to change the NSDate's to NSStrings at a later date, but for now they are NSDates.
So, now to show you what is being parsed. The JSON returns the following.
[{"note id":"525","note title":"Car","note summary":"","note content":"","note created":"1297130179","note_updated":"1297233954"},
{"note id":"252","note title":"Premium Users","note summary":"","note content":"","note created":"1296046367","note_updated":"1296699888"},
{"note id":"253","note title":"Welcome!","note summary":"","note content":"","note created":"1296046367","note_updated":"1296561871"}]
What I am wanting to do is create an entity "Event" and each entity stores the respective values for that event. Easy, right? Obviously not for me.
What I have tried...
NotaciousAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSManagedObject *newNote;
newNote = [NSEntityDescription insertNewObjectForEntityForName:#"Event" inManagedObjectContext:context];
[newNote setValue:[object valueForKey:#"note title"] forKey:#"title"];
[newNote setValue:[object valueForKey:#"note summary"] forKey:#"summary"];
[newNote setValue:[object valueForKey:#"note updated"] forKey:#"updated"];
NSError *error;
[context save:&error];
Yet this returns an error.
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unacceptable type of value for attribute: property = "title"; desired type = NSString; given type = __NSArrayI; value = (
Car,
"Premium Users",
"Welcome!"
).'
Any ideas or code samples would help. I really need to get this fixed, all dependent on how this is being stored.
EDIT
Here's how we build the request and parse the string returned.
NSDictionary *params = [NSDictionary dictionaryWithObject:api_key forKey:#"api_key"];
[[LRResty client] get:#"http://notacio.us/api/note" parameters:params withBlock:^(LRRestyResponse *response){
if(response.status == 200) {
NSLog(#"Pulling the users notes \n%#", [response asString]);
// Create SBJSON object to parse JSON
SBJSON *parser = [[SBJSON alloc] init];
// parse the JSON string into an object - assuming [response asString] is a NSString of JSON data
NSDictionary *object = [parser objectWithString:[response asString] error:nil];
EDIT
Just thought I'd let people know that I'm currently using the Resty RESTful framework to make my calls to my own API. I thought this was the best alternative and easiest way for myself to build a wrapper for it. Here is the full request.
Resty documentation.
-(void)pullNotes {
NSDictionary *params = [NSDictionary dictionaryWithObject:api_key forKey:#"api_key"];
[[LRResty client] get:url parameters:params withBlock:^(LRRestyResponse *response){
if(response.status == 200) {
NSLog(#"Pulling the users notes \n%#", [response asString]);
// Create SBJSON object to parse JSON
SBJSON *parser = [[SBJSON alloc] init];
// parse the JSON string into an object - assuming [response asString] is a NSString of JSON data
NSDictionary *object = [parser objectWithString:[response asString] error:nil];
NotaciousAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSManagedObject *newNote;
newNote = [NSEntityDescription insertNewObjectForEntityForName:#"Event" inManagedObjectContext:context];
[newNote setValue:[object valueForKey:#"note title"] forKey:#"title"];
[newNote setValue:[object valueForKey:#"note summary"] forKey:#"summary"];
[newNote setValue:[object valueForKey:#"note updated"] forKey:#"updated"];
NSError *error;
[context save:&error];
}
if (response.status == 404) {
NSLog(#"FAIL\n%#", [response asString]);
}
}];
}
EDIT
So, now that I have fixed the JSON issue and am grabbing the individual strings and such from each array, I'm having issues storing the parsed strings into Core Data.
I'll show you what I currently have.
[newNote ] is the name given to the Core Data entity in the header file of the following.
-(void)pullNotes {
UIApplication *app = [UIApplication alloc];
app.networkActivityIndicatorVisible = YES;
NSDictionary *params = [NSDictionary dictionaryWithObject:api_key forKey:#"api_key"];
[[LRResty client] get:#"http://notacio.us/api/note" parameters:params withBlock:^(LRRestyResponse *response){
if(response.status == 200) {
NSLog(#"Pulling the users notes \n%#", [response asString]);
// Create SBJSON object to parse JSON
SBJSON *parser = [[SBJSON alloc] init];
// parse the JSON string into an object - assuming [response asString] is a NSString of JSON data
NSDictionary *object = [parser objectWithString:[response asString] error:nil];
NSArray *notes = [object valueForKey:#"result"];
for (NSDictionary *singleNote in notes){
// newNote.created = [singleNote objectForKey:#"note created"]; Need to work on parsing these properly...
// newNote.updated = [singleNote objectForKey:#"note updated"]; Need to work on parsing these properly...
NSString *notetitle = [singleNote objectForKey:#"note title"];
NSString *notesummary = [singleNote objectForKey:#"note summary"];
NSString *noteid = [singleNote objectForKey:#"note id"];
NSString *notecontent = [singleNote objectForKey:#"note content"];
// NSDate *createdDate =
// NSDate *updatedDate =
// If appropriate, configure the new managed object.
[newNote setValue:notetitle forKey:#"title"];
[newNote setValue:notesummary forKey:#"summary"];
[newNote setValue:noteid forKey:#"ID"];
[newNote setValue:notecontent forKey:#"content"];
NSLog(#"value is %#", notetitle);
NSError *error = nil;
if (![newNote.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. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.
*/
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
[tableView reloadData];
app.networkActivityIndicatorVisible = NO;
}
}
if (response.status == 404) {
NSLog(#"FAIL\n%#", [response asString]);
app.networkActivityIndicatorVisible = NO;
}
}];
}
#end
However, running this code doesn't actually store the strings into the Core Data entity. As you can see it isn't finalised, a lot of commented code, but the basis is there. ANYWAY, I'm curious as to whether or not it is how I actually implement this in the pulling of the notes itself from the RootViewController...
In viewDidLoad() I'm calling the following...
ntIndex = [IndexNotes alloc];
ntIndex.api_key = api_key;
ntIndex.tableView = self.tableView;
[ntIndex pullNotes];
[ntIndex release];
[self.tableView reloadData];
}
Any help would be great, I'd love to hear what others think the issue is. I don't get any errors with the above code, just nothing is inserted into the Core Data and in turn isn't displayed in my UITableView in RootViewController...
The first thing I would do is log what this line returns:
[object valueForKey:#"note title"]
You'll find it's not the string you're expecting, but is an array of note titles.
eg:
NSLog(#"value is %#", [object valueForKey:#"note title"]);
Then you'll either need to fix your JSON or change the way you parse it.
Edit:
So when I say fix your JSON, I'm no expert, but I think it should look like this:
{"result":[{"note id":"525","note title":"Car","note summary":"","note content":"","note created":"1297130179","note_updated":"1297233954"}, {"note id":"252","note title":"Premium Users","note summary":"","note content":"","note created":"1296046367","note_updated":"1296699888"}, {"note id":"253","note title":"Welcome!","note summary":"","note content":"","note created":"1296046367","note_updated":"1296561871"}]}
Then:
NSDictionary *object = [parser objectWithString:[response asString] error:nil];
NSArray notes = [object valueForKey:#"result"];
for (NSDictionary *singleNote in notes){
[singleNote objectForKey:"note title"] //this gives you the title of the current note your on
}
It's to do with the fact [object valueForKey:#"note title"] is returning an array.
You'll like want to insert something more like [[object valueForKey:#"note title"] objectAtIndex:1] to take an object out of the array. However working out what index you want to insert from the title array is the hardest part.
Tim
EDIT:
Having looked into some others responses its apparent it's returning all the titles in one object. There's something either incredibly funky going on with your JSON. A way around this would be to possibly for loop over your results set from your JSON request and using the index from this loop to insert the correct title.
eg:
int count;
for (count = 0; count < [[object valueForKey:#"note title"] count]; count++)
{
// Do your other insert stuff here
[newNote setValue:[[object valueForKey:#"note title"] objectAtIndex:count] forKey:#"title"];
}
again this is just a dirty example of what you could possibly do so solve this problem.

"Save" in CoreData-apps

I've here a CoreData app (no document-based), 1 entity and 1 tableview for edit/add/remove "instances" of the entity. Now I can manual add and save but I would like to
a) save automaticly changes
b) add automaticly some "instances" with the first start.
I think a) can be solved with NSNotifications. But which to use by entities?
Any ideas how to solve a) or b)?
Thanks for every answer. =)
Autosave can be a bit trickier than you'd first expect sometimes, since there may be times when your application data is in an invalid state (for instance, when the user is editing an entity) and either cannot be saved or it would not make sense to save. There's no easy setAutosaves:YES property unfortunately, so you'll have to implement it yourself. Using a notification to save after certain actions is one way to do it, you could also set up a timer to save periodically if it makes sense for your application.
To populate an empty data file, just check to see if the data store is empty at launch (applicationDidFinishLaunching and awakeFromNib are two possible places to put this), and if it is insert some entities as normal. The only tricky part is disabling undo management during the process. Here's an example from one of my applications:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification;
{
NSURL *fileURL = [NSURL fileURLWithPath:[self.applicationSupportFolder stringByAppendingPathComponent:WLDataFileName]];
NSManagedObjectModel *model = [NSManagedObjectModel mergedModelFromBundles:nil];
NSPersistentStoreCoordinator *coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
NSManagedObjectContext *context = [[NSManagedObjectContext alloc] init];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[coordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:fileURL options:nil error:NULL];
[context setPersistentStoreCoordinator:coordinator];
[request setEntity:[NSEntityDescription entityForName:#"Shelf" inManagedObjectContext:context]];
if ( [context countForFetchRequest:request error:NULL] == 0 )
[self _populateEmptyDataStore:context];
_managedObjectContext = [context retain];
[request release];
[coordinator release];
[context release];
// finish loading UI, etc...
}
- (void)_populateEmptyDataStore:(NSManagedObjectContext *)context;
{
[[context undoManager] disableUndoRegistration];
WLSmartShelfEntity *allItems = [NSEntityDescription insertNewObjectForEntityForName:#"SmartShelf" inManagedObjectContext:context];
WLSmartShelfEntity *trash = [NSEntityDescription insertNewObjectForEntityForName:#"SmartShelf" inManagedObjectContext:context];
allItems.name = NSLocalizedString( #"All Items", #"" );
allItems.predicate = [NSPredicate predicateWithFormat:#"isTrash = FALSE"];
allItems.sortOrder = [NSNumber numberWithInteger:0];
allItems.editable = [NSNumber numberWithBool:NO];
trash.name = NSLocalizedString( #"Trash", #"" );
trash.predicate = [NSPredicate predicateWithFormat:#"isTrash = TRUE"];
trash.sortOrder = [NSNumber numberWithInteger:2];
trash.editable = [NSNumber numberWithBool:NO];
[context processPendingChanges];
[[context undoManager] enableUndoRegistration];
DebugLog( #"Filled empty data store with initial values." );
}
Have a look at this thread on the Apple Mailing lists regarding autosave and Core Data.