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

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.

Related

Reload TableView Data from DB

In my app i git dat from DB by php file in internet and data shown in a Table view but i need to reload my data every minute, i can get the new data every minute but i cant replace it in the table view.
1) Do you know how to do it?
2) If you know how to get my code more simple, and delete that unNeeded codes? I'll be thanks to you.
My ViewController.m
#import "ViewController.h"
#import "CJSONDeserializer.h"
#implementation ViewController
#synthesize tblMain, rows;
NSURL *url;
NSString *jsonreturn;
NSData *jsonData;
NSError *error;
NSDictionary *dict;
UITableViewCell *cell;
static NSString *CellIdentifier;
- (void)viewDidLoad{
[super viewDidLoad];
[self GetData];
}
-(void)GetData{
url = [NSURL URLWithString:#"http://ar2.co/savola/"];
jsonreturn = [[NSString alloc] initWithContentsOfURL:url];
NSLog(jsonreturn);
jsonData = [jsonreturn dataUsingEncoding:NSUTF32BigEndianStringEncoding];
dict = [[[CJSONDeserializer deserializer] deserializeAsDictionary:jsonData error:&error] retain];
rows = [dict objectForKey:#"savola"];
NSLog(#"Array: %#",rows);
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [rows count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}
dict = [rows objectAtIndex: indexPath.row];
cell.textLabel.text = [NSString stringWithFormat:#"%# - %#", [dict objectForKey:#"company"], [dict objectForKey:#"price"]];
cell.detailTextLabel.text = [dict objectForKey:#"time"];
return cell;
}
#end
To force a table to reload its information, call [self.tableView reloadData] from your view controller class. That will call all of the data source methods again, and it will update the display as well.
You should reload the table after fetching the new data from server. Like in your GetData method :
- (void)GetData
{
url = [NSURL URLWithString:#"http://ar2.co/savola/"];
jsonreturn = [[NSString alloc] initWithContentsOfURL:url];
NSLog(jsonreturn);
jsonData = [jsonreturn dataUsingEncoding:NSUTF32BigEndianStringEncoding];
dict = [[[CJSONDeserializer deserializer] deserializeAsDictionary:jsonData error:&error] retain];
rows = [dict objectForKey:#"savola"];
NSLog(#"Array: %#",rows);
[yourTable reloadData];
}
You need to use reloadData method to reload your table view to display the new data.
But as you mentioned- "but i need to reload my data every minute"
So for this you can check the recieved data with existing data, and if something is changed in new data then only reload the table, else skip that.
If you reload your table every one minute unneccesary without change in data, that will be not correct and also that will slow down your app.
In this kind of situation I would recommend you look at using NSFetchedResultsController. It will automatically update you table only when it is required.

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!

Reading url image from plist string

I have a plist with dictionary.
In the dictionary i have a string called "cellPic" that have url address of an image.
I'm trying to populate my table view with images that i put on my dropbox account & read them through the plist string.
("arrayFromPlist" is my array)
The problem is that when i run it, i'm getting an error in the console:
[__NSCFDictionary objectAtIndex:]: unrecognized selector
This is my code:
-(void) readPlistFromDocs
{
// Path to the plist (in the Docs)
NSString *rootPath =
[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES) objectAtIndex:0];
NSString *plistPath = [rootPath stringByAppendingPathComponent:#"Data.plist"];
NSLog(#"plistPath = %#",plistPath);
// Build the array from the plist
NSMutableArray *arrayFromDocs = [[NSMutableArray alloc] initWithContentsOfFile:plistPath];
if (arrayFromDocs)
{
NSLog(#"\n content of plist file from the documents \n");
NSLog(#"Array from Docs count = : %d", [arrayFromDocs count]);
}
arrayFromPlist = [[NSArray alloc] initWithArray:arrayFromDocs];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
// Returns the number of rows in a given section.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [arrayFromPlist count];
NSLog(#"Array SIZE = %d",[arrayFromPlist count]);
}
- (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
NSURL *url = [[NSURL alloc] initWithString:[[arrayFromPlist objectAtIndex:indexPath.row] objectForKey:#"cellPic"]];
NSData *urlData = [[NSData alloc] initWithContentsOfURL:url];
[[cell imageView] setImage:[UIImage imageWithData:urlData]];
return cell;
}
My other question is - how can i load the images asynchronous when i read the url from the plist string?
I tried to find an example for that but i found only asynchronous without uisng plist.
Thanks.
Change Following line
NSDictionary *arrayFromDocs = [[NSDictionary alloc] initWithContentsOfFile:plistPath];
Best Tutorial for load the images asynchronous
Hope, this will help you..

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.

iPhone UITableView populateing from connectionDidFinishLoading

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.