iPhone UITableView populateing from connectionDidFinishLoading - iphone

I have been trying for hours to figure this out. I have some JSON from a NSURLConnection. This is working fine and I have parsed it into an array. But I can't seem to get the array out of the connectionDidFinishLoading method. I an am getting (null) in the UITableViewCell method. I am assuming this is a scope of retain issue, but I am so new to ObjC I am not sure what to do. Any help would be greatly appreciated.
Cheers.
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
[connection release];
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
[responseData release];
SBJSON *json = [[SBJSON alloc] init];
NSDictionary *results = [json objectWithString:responseString];
self.dataArray = [results objectForKey:#"data"];
NSMutableArray *tableArray = [[NSMutableArray alloc] initWithObjects:nil];
for (NSString *element in dataArray) {
//NSLog(#"%#", [element objectForKey:#"name"]);
NSString *tmpString = [[NSString alloc] initWithString:[element objectForKey:#"name"]];
[tableArray addObject:tmpString];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
// Configure the cell.
//cell.textLabel.text = [self.tableView objectAtIndex:indexPath.row];
cell.textLabel.text = [self.tableArray objectAtIndex:indexPath.row];
NSLog(#"%#", tableArray);
return cell;
}

Solution:
After taking kubi and st3fan's advice with self.tableArray I found I had to reload the tableView with [self.tableView reloadData];

Get rid of the [connection release] in the 2nd line. The connection object comes in autoreleased, so this could cause crashes.
It looks like you've got a property named tableArray? If so, you're redeclaring the name in this method (you should have gotten a compiler warning).
On second thought, here's how the 2nd 1/2 of the method should look:
NSMutableArray *tmpArray = [[NSMutableArray alloc] initWithObjects:nil];
for (NSString *element in dataArray) {
[tmpArray addObject:[element objectForKey:#"name"]];
}
self.tableArray = tmpArray;
[tmpArray release];

In connectionDidFinishLoading: you use declare tableArray as a local variable. Therefore it will never be assigned to self.tableArray.

I had the same problem and I resolved it reloading the table.
I inserted this line at the end of connectionDidFinishLoading function
[self.tableView reloadData];
and it works.

Related

JSON Object to NSArray

I have to following JSON response from a server:
{
"theSet": [
],
"Identifikation": 1,
"Name": "Casper",
"Adress": "Lovis 23",
"Location": "At home",
"Information": "The first, the second and the third",
"Thumbnail": "none",
}
I am retrieving the data like so:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSLog(#"connectionDidFinishLoading");
NSLog(#"Succeeded! Received %d bytes of data",[data length]);
NSError *myError = nil;
NSDictionary *res = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:&myError];
news = [NSArray arrayWithObjects:[res allKeys], [res allValues], nil];
NSLog(#"%#", news);
//[mainTableView reloadData];
}
Then I want to insert all the JSON data into an array, so I can display the data in my tableview.
My tableview code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MainCell"];
if(cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"MainCell"];
}
cell.textLabel.text = [[news objectAtIndex:indexPath.row] objectForKey:#"Name"];
cell.detailTextLabel.text = [[news objectAtIndex:indexPath.row] objectForKey:#"Adress"];
return cell;
}
But my app crashes with the error:
-[__NSArrayI objectForKey:]: unrecognized selector sent to instance.
How can I insert the JSON object into an NSArray, so I can display it in my tableview?
EDITED:
I reviewed your code again and what I previously answered was wrong.
When generating your news, you are putting 2 NSArray objects in it. The first containing all keys, and the second containing all values in your JSON.
In order to display the names of each object in your JSON, you should be simply doing
news = [res allKeys];
jsonResult = res;
// store your json if you want to use the values!
Note they will be unordered.
On your cell, you can do:
NSString *key = [news objectAtIndex:indexPath.row];
cell.textLabel.text = key;
id object = [jsonResult valueForKey:key];
cell.detailTextLabel.text = // do something depending on your json type which can have different values
The error you have
[__NSArrayI objectForKey:]: unrecognized selector sent to instance.
Tells you everything you need to know.
This says NSArray does not understand objectForKey. If you read the documentation provided by Apple, you will see this.
Your code
cell.textLabel.text = [[news objectAtIndex:indexPath.row] objectForKey:#"Name"];
Is expecting the news NSArray to return an object that responds to objectForKey - most likely an NSDictionary. The code you have for extracting your JSon data
NSDictionary *res = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:&myError];
news = [NSArray arrayWithObjects:[res allKeys], [res allValues], nil];
Is just taking all of the dictionaries and extracting the keys into the array.
You need to look at these lines of your code - this is where you are going wrong.
Look at the NSJSONSerialization reference and the releated sample code that it links to.
I found a simple solution myself, that fits my project better:
I just did the following:
NSDictionary *res = [NSJSONSerialization JSONObjectWithData:data options:0 error:&myError];
NSArray news = [NSArray arrayWithObject:res];
and with that I am able to use the following code to display the JSON contents in my tableview.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MainCell"];
if(cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"MainCell"];
}
cell.textLabel.text = [[news objectAtIndex:indexPath.row] valueForKey:#"name"];
cell.detailTextLabel.text = [[news objectAtIndex:indexPath.row] objectForKey:#"Location"];
return cell;
}

self performSelector:#selector(loadData) withObject:nil - not working

I use:
self performSelector:#selector(loadData) withObject:nil...
it look like working with some command only in "loadData" but the rest are not.
Here is my viewdidload:
- (void)viewDidLoad
{
[super viewDidLoad];
[mActivity startAnimating];
[self performSelector:#selector(loadData) withObject:nil afterDelay:2];
//[mActivity stopAnimating];
}
and here is loadData:
-(void)loadData
{
[mActivity startAnimating];
NSLog(#"Start LoadData");
AppDelegate *delegate=(AppDelegate *)[[UIApplication sharedApplication] delegate];
NSString *selectData=[NSString stringWithFormat:#"select * from k_proverb ORDER BY RANDOM()"];
qlite3_stmt *statement;
if(sqlite3_prepare_v2(delegate.db,[selectData UTF8String], -1,&statement,nil)==SQLITE_OK){
NSMutableArray *Alldes_str = [[NSMutableArray alloc] init];
NSMutableArray *Alldes_strAnswer = [[NSMutableArray alloc] init];
while(sqlite3_step(statement)==SQLITE_ROW)
{
NSString *des_strChk= [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement,3)];
if ([des_strChk isEqualToString:#"1"]){
NSString *des_str= [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement,4)];
[Alldes_str addObject:des_str];
}
}
Alldes_array = Alldes_str;
Alldes_arrayAnswer = Alldes_strAnswer;
}else{
NSLog(#"ERROR '%s'",sqlite3_errmsg(delegate.db));
}
listOfItems = [[NSMutableArray alloc] init];
NSDictionary *desc = [NSDictionary dictionaryWithObject:
Alldes_array forKey:#"description"];
[listOfItems addObject:desc];
//[mActivity stopAnimating];
NSLog(#"Finish loaData");}
it give me only printing 2 line, but did not load my Data to the table, but if I copy all the code from inside "loadData" and past in "viewDidLoad", it load the data to the table.
Any advice or help please.
A few things: If you see any NSLog output at all, then the performSelector is succeeding. You should change the title of your question.
If you are trying to load data into a table, the method should end with telling the UITableView to reloadData (or a more elaborate load using begin/end updates).
If the listOfItems is the data supporting the table, get this working first by hard-coding something like this:
-(void)loadData {
listOfItems = [NSArray arrayWithObjects:#"test1", #"test2", nil];
[self.tableView reloadData];
return;
// keep all of the code you wrote here. it won't run until you remove the return
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
NSString *string = [listOfItems objectAtIndex:indexPath.row];
cell.textLabel.text = string;
return cell;
// keep all of the code you probably wrote for this method here.
// as above, get this simple thing running first, then move forward
}
Good luck!

iOS - Unable to access NSMutableArray in didSelectRowAtIndexPath?

I am unable to access my NSMutableArray in didSelectRowAtIndexPath although i am able to access it in cellForRowAtIndexPath.
Here is my code :-
- (void)viewDidLoad
{
NSString *path = [[NSBundle mainBundle] pathForResource:#"drinks" ofType:#"plist"];
self.drinkArray = [[NSMutableArray alloc] initWithContentsOfFile:path];
NSLog(#"%#", self.drinkArray);
[super viewDidLoad];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
NSLog(#"I am inside cellForRowAtIndexPath");
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
// Configure the cell.
NSDictionary *dict = [self.drinkArray objectAtIndex:indexPath.row];
cell.textLabel.text = [dict objectForKey:#"name"];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
[dict release];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
DrinkDetails *detailViewController = [[DrinkDetails alloc] initWithNibName:#"DrinkDetails" bundle:nil];
// ...
// Pass the selected object to the new view controller.
//detailViewController.drink = [self.drinkArray objectAtIndex:indexPath.row];
NSLog(#"%#", self.drinkArray);
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
}
Sometime NSLog prints some stupid output and sometime it gives me an error "EXC_BAD_ACCESS".
Please take a look and check what is wrong with my code.
Any help would be appreciated.
Thanks.
You have one (really two) issues, but the main one is in your -cellForRowAtIndexPath: method:
[dict release];
Get rid of this line and it should work just fine.
The reason why this fixes your issue is because -objectAtIndex: simply returns a pointer to the requested object in memory, therefore you do not (and should not) send the -release message to that object because the NSArray obtained ownership of the object when it was inserted. Sending -release to this object reference effectively deallocates the object in memory and now this indice in the NSArray is pointing to garbage memory. BAD BAD BAD
The other issue is that you have a memory leak here:
self.drinkArray = [[NSMutableArray alloc] initWithContentsOfFile:path];
You are sending the -retain message to an object reference that you already have ownership of by way of sending -alloc. (This of course assumes that your #property has the retain setter modifier)
To fix this issue, simply send the -autorelease message to this instance:
self.drinkArray = [[[NSMutableArray alloc] initWithContentsOfFile:path] autorelease];
Don't release an object unless it was created with alloc or obtained with a method beginning with new or copy or explicitly retain'ed. (NARC)
In this case:
NSDictionary *dict = [self.drinkArray objectAtIndex:indexPath.row];
was not returned retained so you do not have ownership and should not release it.
By the same token:
self.drinkArray = [[NSMutableArray alloc] initWithContentsOfFile:path];
is alloc'ed so it needs to be released or obtained with a convince method that will return an autoreleased object:
self.drinkArray = [NSMutableArray arrayWithContentsOfFile:path];
You shouldn't [dict release]in cellForRowAtIndexPath. objectAtIndex does not retain it, so it may be sweeped out of your array when you release it.

Json Parser output display in tableview

I am trying to parse using JSON Parser and the result which i get i have to put it into table view. I've passed a constant key value and a string .
Is there parsing steps wrong? or missed.
I have included the code for the JSON parser.
Thanks in advance.
SBJSON *parser = [[SBJSON alloc] init];
NSString *urlString =[NSString stringWithFormat:#"http://api.shopwiki.com/api/search?key=%#&q=%#",apiKey, string];
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL: url];
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSString *json_string = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
NSMutableArray *statuses = [[NSMutableArray alloc]init];
statuses = [parser objectWithString:json_string error:nil];
NSLog(#"Array Contents: %#", statuses);
NSMutableArray *statuses0 = [[NSMutableArray alloc]init];
statuses0 = [statuses valueForKey:#"offers"];
NSLog(#"Array Contents: %#", statuses0);
//For Title
NSMutableArray *statuses1 = [[NSMutableArray alloc]init];
statuses1 = [[[statuses valueForKey:#"offers"] valueForKey:#"offer"]valueForKey:#"title"];
NSLog(#"Array Contents 4 Title: %#", statuses1);
Here in statuses1 array i get 20 objects which are all titles, now i just want to display that titles into tableview:-
snippet code for tableview:-
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSLog(#"status count:%d",[statuses1 count]);
return [statuses1 count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"Inside Tableview");
int counter=indexPath.row;
NSString *CellIdentifier = [NSString stringWithFormat:#"%d",counter];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
cell.selectionStyle=UITableViewCellSelectionStyleNone;
}
NSLog(#"Inside Tableview 1");
cell.textLabel.text=[statuses1 objectAtIndex:indexPath.row];
NSLog(#"Inside Tableview 2");
return cell;
}
I get Bad excess exception whten it hits on :-
cell.textLabel.text=[statuses1 objectAtIndex:indexPath.row];
Please give me the solution
thanks in advance:-
If you're getting EXC_BAD_ACCESS on that line, it's probably because statuses1 has been released by the time cellForRowAtIndexPath is called. What block of code is this line in?
NSMutableArray *statuses1 = [[NSMutableArray alloc]init];
The statuses1 variable above is local to whatever scope you've declared it in. Do you then assign it to your UITableViewController.statuses1 ivar? Is that a retained property?

UITableView isn't loading the data from my plist file what am i doing wrong?

Okay, so I have an app that I'm trying to get to populate a UITableView with the contents of a plist file. I haven't been able to find anyone else having problems doing this and how they fixed it so I'm probably just an idiot but I need to know how all the same!
I'm sure the error is somewhere in my viewDidLoad section or my tableview section...but maybe someone else can give me a better idea.
-(void)viewDidLoad {
NSString *path = [[NSBundle mainBundle] pathForResource:#"datam" ofType:#"plist"];
NSArray *array = [[NSArray alloc] initWithContentsOfFile:path];
self.listData = array;
[array release];
[super viewDidLoad];
}
#pragma mark -
#pragma mark Table View Data Source Methods
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section {
return [self.listData count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *SimpleTableIdentifier = #"Identifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:Identifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:SimpleTableIdentifier] autorelease];
}
NSUInteger row = [indexPath row];
cell.textLabel.text = [listData objectAtIndex:row];
return cell;
}
I think [super viewDidLoad] should be foremost in the viewDidLoad method.
NSString *path = [[NSBundle mainBundle] pathForResource:#"datam" ofType:#"plist"];
NSArray *array = [[NSArray alloc] initWithContentsOfFile:path];
This seems a little odd; is your file named "datam.plist"?
Try using some NSLogs() throughout your code to see what the status of your array is at any given time:
NSLog(#"%# has %i elements",ARRAY_OBJECT,[ARRAY_OBJECT count]);
Check the GDB output in XCode while the application runs to see if the results match what you expect.
self.listData = array; [array release];
Try this instead:
self.listData = [array copy]; [array release];
NSArray objects are pointers; when you set self.listData = array, you really tell anything looking for listData to look in the memory address originally occupied by array. When you release array, it vacates that memory address, thus making the pointer point to nothing.