Extract additional NSString from array of JSON parsing data for TableView - objective-c

I'm parsing my json file and showing it in a grouped table view.
-(void) connectionDidFinishLoading:(NSURLConnection *)connection
{
NSDictionary *allDataDictionary = [NSJSONSerialization JSONObjectWithData:webData options:0 error:nil];
NSDictionary *parks = [allDataDictionary objectForKey:#"Parks"];
NSArray *arrayOfParks = [parks objectForKey:#"Park"];
for (NSDictionary *diction in arrayOfParks) {
NSString *hebName = [diction objectForKey:#"hebName"];
NSString *engName = [diction objectForKey:#"engName"];
NSString *latitude = [diction objectForKey:#"lat"];
NSString *longtitude = [diction objectForKey:#"long"];
[array addObject:hebName];
}
[[self myTableView] reloadData];
}
-(void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *details = [array objectAtIndex:indexPath.row];
[[[UIAlertView alloc] initWithTitle:#"B7Tour" message:details delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil] show];
}
It works very well and I present in my table view the engName.
Clicking on the item at the table view will pop up an alert with the engName itself.
My question is: how to extract the particular latitude and longtitude and save them?
I know how to present them in the table view but I want to extract and save them for additional usage.
Any ideas?

You might want to have the array of dictionaries exist outside this method.
Then you can access them any time.
Then you can maintain another ivar that is your current selection in the table view.
From there it is pretty straight forward to call the objectForKey: on the currently selected object.

Related

CoreData and UITableView: display values in cells

I'm working with Core Data and web service, I want to add my data to my table,
but I don't know how should I call them, would you please help me, since when I used this way it's not working.
Here is my method for update database in my HTTP class
- (void)updateLocalCardsDataBase:(NSArray*) cardsArray
{
//check if current user has cards in local database
NSManagedObjectContext* managedObjectContext = [(AppDelegate*) [[UIApplication sharedApplication] delegate] managedObjectContext];
for(NSDictionary *cardDic in cardsArray)
{
Card *card = [NSEntityDescription insertNewObjectForEntityForName:#"Card" inManagedObjectContext:managedObjectContext];
card.remote_id = [NSNumber numberWithInt:[[cardDic objectForKey:#"id"] intValue]];
card.stampNumber = [NSNumber numberWithInt:[[cardDic objectForKey:#"stampNumber"] intValue]];
card.createdAt = [NSDate dateWithTimeIntervalSince1970:[[cardDic objectForKey:#"createdAt"] intValue]];
[managedObjectContext lock];
NSError *error;
if (![managedObjectContext save:&error])
{
NSLog(#"Whoops, couldn't save: %#", [error localizedDescription]);
NSLog(#"Failed to save to data store: %#", [error localizedDescription]);
NSArray* detailedErrors = [[error userInfo] objectForKey:NSDetailedErrorsKey];
if(detailedErrors != nil && [detailedErrors count] > 0) {
for(NSError* detailedError in detailedErrors) {
NSLog(#" DetailedError: %#", [detailedError userInfo]);
}
}
else {
NSLog(#" %#", [error userInfo]);
}
}
[managedObjectContext unlock];
}
Here is my table:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
// NSManagedObjectContext* managedObjectContext = [(AppDelegate*) [[UIApplication sharedApplication] delegate] managedObjectContext];
static NSString *CellIdentifier = #"CardsCell";
CardCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil){
NSArray *objects = [[NSBundle mainBundle] loadNibNamed:#"CardCell" owner:nil options:nil];
for (id currentObject in objects)
{
if([currentObject isKindOfClass:[UITableViewCell class]])
{
cell = (CardCell *) currentObject;
break;
}
}
NSDictionary *f = [_cards objectAtIndex:indexPath.row];
cell.stampId.text = [f objectForKey:#"stampNumber"];
NSLog(#"%#fdssfdfddavds",[f objectForKey:#"stampNumber"]);
cell.createdAt.text = [f objectForKey:#"createdAt"];
cell.CardId.text = [f objectForKey:#"id"];
return cell;
}
Edit:
My problem is how I can show data in a UITableView
Before call [tableView reloadData], you need to get a data source first. You will get back an array of your data models, not an NSDictionary. You can place the my example method (or a variation that suits you best) where ever best suits your needs, but this one will not filter or sort the models, it will only get all of them. Also, I will place the method in your view controller that stores the table view:
-(NSArray*)getMycards {
NSManagedObjectContext *context = [(AppDelegate*) [[UIApplication sharedApplication] delegate] managedObjectContext];
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:#"Card" inManagedObjectContext:context];
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
NSError *error;
[request setEntity:entityDescription];
NSArray *cards = [context executeFetchRequest:request error:&error];
// now check if there is an error and handle it appropriatelty
// I usually return 'nil' but you don't have if you don't want
if ( error != nil ) {
// investigate error
}
return cards;
}
I recommend creating a property #property NSArray *cards in the view controller where you place your table, it will be easier to manage. One assumption I have made (since I have no other information about your view controller, a property named 'tableView' is declared in your view controller's header file (#property UITableView *tableView;), adjust the naming as needed.
With the above method, when you want to populate your array before loading the table's data:
// you put this block of code anywhere in the view controller that also has your table view
// likely in 'viewDidLoad' or 'viewDidAppear'
// and/or anywhere else where it makes sense to reload the table
self.cards = [self getMyCards];
if ( self.cards.count > 0 )
[self.tableview reloadData];
else {
// maybe display an error
}
Now, your cellForRowAtIndexPath should look like
-(UITableViewCell*tableView:tableView cellForRowAtIndexPath {
UITbaleViewCell *cell = ...;
// creating the type of cell seems fine to me
.
.
.
// keep in mind I don't know the exact make up of your card model
// I don't know what the data types are, so you will have to adjust as necessary
Card *card = self.cards[indexPath.row];
cell.stampId.text = [[NSString alloc] initWithFormat:#"%#",card.stamp];
cell.createdAt.text = [[NSString alloc] initWithFormat:#"%#",card.createdAt];
// you might want format the date property better, this might end being a lot more than what you want
cell.CardId.text = [[NSString alloc] initWithFormat:#"%#",card.id];
return cell;
}
Core Data is extremely powerful, I highly recommend the Core Data overview, followed by the Core Data Programming Guide.

Why would a property essentially disappear? Obj-C, Cocoa

I am quite stumped. I have an app with a class for storing item details. Called LEItem. Those items are stored in a store with a class labeled LEItemStore. I have a view with a table of all items. This works fine. If you tap on a row, it sends this message to LogbookFirstViewController.
LogbookFirstViewController *logController = [[LogbookFirstViewController alloc] initForNewItem:NO];
NSArray *items = [[LEItemStore sharedStore] allItems];
LEItem *selectedItem = [items objectAtIndex:[indexPath row]];
NSString *description = [selectedItem description];
NSLog(#"%#", description);
[logController setItem:selectedItem];
[self dismissViewControllerAnimated:YES completion:nil];
That is in a TableView class. In the LogbookFirstViewController.m I have
-(void)setItem:(LEItem *)i{
item = i;
NSString *t = [item description];
NSLog(#"In LogbookFirstViewController, returning %#", t);
}
This is where it gets odd. That works. It outputs the correct item, therefore I would think everything would be okay. But it's not. item is a class-level property, so it should stay, but it doesn't. In the same class, I have overrode this method.
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
//NSString *string = [item description];
//NSLog(#"Item = %#", string);
NSLog(#"View did Appear:animated");
int glucoseValue = [item glucose];
NSString *glucoseString = [NSString stringWithFormat:#"%d", glucoseValue];
[glucoseField setText:glucoseString];
int proteinValue = [item protein];
NSString *proteinString = [NSString stringWithFormat:#"%d", proteinValue];
[proteinField setText:proteinString];
int carbsValuue = [item carbs];
NSString *carbsString = [NSString stringWithFormat:#"%d", carbsValuue];
[carbsField setText:carbsString];
int insulinValue1 = [item insulin];
NSString *insulin1String = [NSString stringWithFormat:#"%d", insulinValue1];
[insulinField1 setText:insulin1String];
int insulinValue2 = [item insulin2];
NSString *insulinString2 = [NSString stringWithFormat:#"%d", insulinValue2];
[insulinField2 setText:insulinString2];
//NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
//[dateFormatter setDateStyle:NSDateFormatterShortStyle];
//[dateFormatter setTimeStyle:NSDateFormatterShortStyle];
//NSLog(#" The item was created on %#", [dateFormatter stringFromDate:[item dateCreated]]);
//[dateButton setTitle:[dateFormatter stringFromDate:[item dateCreated]] forState:UIControlStateNormal];
NSString *t = [item description];
NSLog(#"Loading view... Returns: %#", t);
}
I know that it isn't the cleanest code, but the idea is the same. It uses exactly the same code as the setItem: method. However, this always returns (null). Why? The property appears to go missing at viewWillAppear.
Thanks.
EDIT
I solved the problem. As you can see, the checked answer below did give the right idea, here is what I did to solve it. The problem was that when I sent setItem: I used this code to get LogbookFirstViewController
LogbookFirstViewController *logController = [[LogbookFirstViewController alloc] initForNewItem:NO];
As I know see, that created a new instance of LogbookFirstViewController, so therefore, the existing one did not change it's Item property, as properties are assigned to one instance. Therefore, I was only changing the value of Item for this "invisible" property.
To solve this, one must get the existing instance of the viewController. To do this I did the following:
In LogbookFirstViewController.h I added this property
#property (assign) LogbookFirstViewController *instance;
Then, synthesize instance in your .m and in the same placed I added this to viewDidLoad
- (void)viewDidLoad
{
instance = self;
...
Then, in the other viewController, entriesViewController, I added this too the .h
#property (nonatomic, strong) LogbookFirstViewController *logController;
Synthesize it. Then, I just used my didSelectRowAtIndexPath the same way, just using the existing logController
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSArray *items = [[LEItemStore sharedStore] allItems];
LEItem *selectedItem = [items objectAtIndex:[indexPath row]];
NSString *description = [selectedItem description];
NSLog(#"%#", description);
NSLog(#"Setting controller: %#", logController);
[logController setItem:selectedItem];
[self dismissViewControllerAnimated:YES completion:nil];
}
Then it works!
You have a line where you create the LogbookFirstViewController but you don't actually cause it to display anything (push or present). Since it's a local variable, it would appear that whatever instance of that controller is loading its view is not the same one that you initialize in the code you've shown.
You can verify this by adding a couple of NSLog lines, such as:
NSLog(#"Setting controller: %#", logController); // Insert before existing line
[logController setItem:selectedItem];
...and...
[super viewWillAppear:animated];
NSLog(#"Viewing controller: %#", self); // Insert after existing line
For things to work the way you want, those have to print the same address.
You should retain when assigning object to property without ARC:
-(void)setItem:(LEItem *)i{
_item = [i retain];
...
}
If you use property with ARC, then write _item = i;:
-(void)setItem:(LEItem *)i{
_item = i;
...
}

numberOfRowsInSection returning 0 in a threaded viewController

I have a viewController in an app that retrieves Data from JSON, parses it and populates in UITableView. I am using thread to load data so that app does not hang when it is retrieving data.
Problem:
numberOfRowsInSection returns 0 and UITableView does not get populated sometimes when app is started. While sometimes, everything works fine. It is all random :S
Possible Explanation:
The problem is, it seems like, sometimes numberOfRowsInSection is called before data is retrieved. numberOfRowsInSection returns the value of count of a NSMutableArray called 'subjects'. Objects in 'subjects' are added when loadData is called. So the numberOfRowsInSection should return the count of 'subjects' and it should not be called after 'subjects' is populated.
Sometimes when I start the app, numberOfRowsInSection is called after 'subjects' is populated and UITableView shows data but sometimes when I start the app, numberOfRowsInSection is called before 'subjects' is populated and UITableView shows no data.
Code:
Here is my code:
-(void)loadData:(id)sender
{
dispatch_queue_t getRemindersQueue=dispatch_queue_create("reminders JSON downloader with reload Button", NULL);
dispatch_async(getRemindersQueue, ^{
[self getReminders];
dispatch_async(dispatch_get_main_queue(), ^{
self.navigationItem.rightBarButtonItem=sender;
[self.tableView reloadData];
});
});
dispatch_release(getRemindersQueue);
}
-(void)getReminders
{
NSURL * aURL = [NSURL URLWithString: #"http://www.merrycode.com/apps/IELTS/RemindersJSON"];
NSURLRequest *request = [NSURLRequest requestWithURL:aURL cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:10.0];
NSError *responseError=nil;
// Perform request and get JSON back as a NSData object
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&responseError];
if(responseError)
{
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertView *parsingError = [[UIAlertView alloc] initWithTitle:#"Network Error"
message:#"Can not reach the servers. Make sure you are connected to the internet."
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[parsingError show];
});
return;
}
NSString *str = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
NSLog(#" String of Reminders JSON: %#",str);
NSString *newStr= [self stringByRemovingControlCharacters:str];
response = [newStr dataUsingEncoding:NSUTF8StringEncoding];
NSError *jsonParsingError = nil;
NSArray *publicTimeline = [NSJSONSerialization JSONObjectWithData:response options:0 error:&jsonParsingError];
NSLog(#"%#", jsonParsingError);
NSLog(#" publicTimeline Array Count: %d", [publicTimeline count]);
if([publicTimeline count] == 0)
{
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertView *parsingError = [[UIAlertView alloc] initWithTitle:#"Error Retriving Data"
message:#"There was an error reciving data from the server."
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[parsingError show];
});
return;
}
NSDictionary *colleges;
for(int i=0; i<[publicTimeline count];i++)
{
colleges= [publicTimeline objectAtIndex:i];
NSLog(#"Reminders: %#", [colleges objectForKey:#"title"]);
[self.subjects addObject:[colleges objectForKey:#"title"]];
[self.dates addObject:[colleges objectForKey:#"date"]];
[self.description addObject:[colleges objectForKey:#"desc"]];
}
[self.subjectsInNSUserDefaults removeAllObjects];
[self.datesInNSUserDefaults removeAllObjects];
[self.descriptionInNSUserDefaults removeAllObjects];
[self.userDefaults setObject:self.subjects forKey:#"SUBJECTS"];
[self.userDefaults setObject:self.dates forKey:#"DATES"];
[self.userDefaults setObject:self.description forKey:#"DESCRIPTION"];
[self.userDefaults synchronize];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSLog(#"Array Count in numberOfRowsInSection: %d",[self.subjects count]);
return [self.subjects count];
}
Couple of ideas...
You said this is a UIViewController (as opposed to UITableViewController). How are you setting up your UITableView and the delegate? If you are still setting up your UITableView or its delegates while this background thread is running, it is theoretically possible that the background thread could complete before you are done setting up your UITableView, which could create strange issues (and explain why this happens "randomly").
Also, have you checked to make sure your response object is populated with information about colleges in the cases where your UITableView isn't getting populated (and not some sort of other response, or no response at all)? I see where you are checking for response errors, but you seem to assume that if there isn't an error, it will be a response with information about colleges (which may or may not be a safe assumption).
If you're correct about the data retrieval being the problem, then I have also had this problem. My inelegant solution was just to set a timer to populate the table at a time when I knew the data would be loaded.

How to store NSMutableArray to NSUserDefaults and show results in TableView?

I want to save the Notifications which come from server in my application and also make a User Interface to give users the ability of chosing which Notification(message) to read. In a scheduled method my client controls for changes inside the server and the communication is in JSON format. I have parsed it and can see the results in NSLog(#"....",..) too. I also control the status of message from the server, if the status equals to 1 i will save the message and add a node to TableView.. Now, can anyone help me about how to transmit datas in NSMutableArray both to NSUserDefaults and TableView? I can Share code or JSON representation too if you want..
It will be better if you could explain with some code.. Thanks
I decided to share some of my code,
as i have writen under the code too, i want to display NSMutableArray in UITableView
`-(IBAction)Accept:(id)sender
{ userName=[[NSString alloc] initWithString:userNameField.text ];
[userNameField setText:userName];
NSUserDefaults *userNameDef= [NSUserDefaults standardUserDefaults];
[userNameDef setObject:userName forKey:#"userNameKey"];
password =[[NSString alloc] initWithString:passwordField.text];
[passwordField setText:password];
NSUserDefaults *passDef=[NSUserDefaults standardUserDefaults];
[passDef setObject:password forKey:#"passwordKey"];
serverIP=[[NSString alloc] initWithString: serverField.text];
[serverField setText:serverIP];
NSUserDefaults *serverDef=[NSUserDefaults standardUserDefaults];
[serverDef setObject:serverIP forKey:#"serverIPKey"];
[userNameDef synchronize];
[serverDef synchronize];
[passDef synchronize];
UIAlertView *message = [[UIAlertView alloc] initWithTitle:#"BNTPRO "
message:#"Your User Informations are going to be sent to server. Do you accept?"
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:#"Cancel", nil];
[message show];
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
NSString *title = [alertView buttonTitleAtIndex:buttonIndex];
if([title isEqualToString:#"OK"])
{
if([userNameField.text isEqualToString:#""]|| [passwordField.text isEqualToString:#""] || [serverField.text length]<10)
{
UIAlertView *message1 = [[UIAlertView alloc] initWithTitle:#"BNTPRO "
message:#"Your User Informations are not defined properly!"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles: nil];
[message1 show];
[userNameField resignFirstResponder];
[passwordField resignFirstResponder];
return;
}
//## GET code to here**
NSString *str1=[#"?username=" stringByAppendingString:userNameField.text];
NSString *str2=[#"&password=" stringByAppendingString:passwordField.text];
NSString *str3=[str1 stringByAppendingString:str2];
NSString *str4 =[#"http://" stringByAppendingString:serverField.text];
NSURL *url=[NSURL URLWithString:[str4 stringByAppendingString:[#"/ipad/login.php" stringByAppendingString:str3]]];
NSLog(#"%#\n",url);
//get the url to jsondata
NSData *jSonData=[NSData dataWithContentsOfURL:url];
if (jSonData!=nil) {
NSError *error=nil;
id result=[NSJSONSerialization JSONObjectWithData:jSonData options:
NSJSONReadingMutableContainers error:&error];
if (error==nil) {
NSDictionary *mess=[result objectForKey:#"message"];
NSDictionary *messContent=[mess valueForKeyPath:#"message"];
NSDictionary *messDate=[mess valueForKeyPath:#"date"];
NSDictionary *messID=[mess valueForKeyPath:#"ID"];
NSDictionary *messStatus=[mess valueForKey:#"status"];
NSLog(#"%# *** Message %# \n Message Content: %# \n Mesage ID: %# \n Message Date: %#\n \nilhancetin MessageSatus: %#", result, mess, messContent, messID,messDate,messStatus);
NSString*key1=[ result objectForKey:#"key" ];
NSString *s1=[#"http://" stringByAppendingString:serverField.text];
NSString *s2=[s1 stringByAppendingString:#"/ipad/button.php"];
NSURL *url2=[NSURL URLWithString:[s2 stringByAppendingString:[#"?key=" stringByAppendingString:key1]]];
NSLog(#"\n%#\n",url2 );
NSData *data2=[NSData dataWithContentsOfURL:url2];
id result2=[NSJSONSerialization JSONObjectWithData:data2 options:NSJSONReadingMutableContainers error:nil];
NSMutableArray *mesID = [NSMutableArray array];//saving meesages to NSMutableArray
NSMutableArray *status = [NSMutableArray array];
// i logged here and it saves the data, now i want to display my data in table view
`
save it in NSUserDefaults:
[[NSUserDefaults standardUserDefaults]setObject:yourArray forKey:#"theArray"];
get it from NSUserDefaults:
[[NSUserDefaults standardUserDefaults]objectForKey:#"theArray"];
setting values from an array to UITableViewCell:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"TheCell";
UITableViewCell *_cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (_cell == nil) {
_cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
_cell.textLabel.text = [yourArray objectAtIndex:indexPath.row];
return _cell;
}
Hope it helps
update
don't have a Mac nearby at the moment, so my answer might be a bit sloppy.
In your header file don't forget to add UITableViewDelegate and UITableViewDataSource, so it will look somewhat like that:
#interface yourController : UIViewController <UITableViewDelegate, UITableViewDataSource, ... some others if you need it ...> {
then in the implementation file(.m) you can just start typing
-tableview
and then use the autocompletion to get the methods that you need. You will most probably need these 3:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
- (void)tableView: (UITableView *)tableView didSelectRowAtIndexPath: (NSIndexPath *)indexPath
depending on the needs of your app you might need more of them, but these 3 should be there.
For more info about UITableView please check that link: http://developer.apple.com/library/ios/#documentation/uikit/reference/UITableView_Class/Reference/Reference.html

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.