PDA

View Full Version : Reload the table after user makes a change.




jjgraz
May 3, 2009, 05:35 PM
Reloading my TableView...

Current Result: User opens my tableview(I.E. inbox), then, opens DetailView(another TableView, didSelectCell), they are able to modify the entries by clicking one of the buttons, and when going back to parent table, it is not updated. I close application, and open it again....And finally the table is reloaded acurratly.


Desired Result: When user opens my tableview(I.E. inbox), further, opens DetailView(another TableView, didSelectCell), they are able to modify the entry and when going back to parent table, Cell and attached images are updated. For Example: Incoming New Messeges, come into table with specific image in cell, and read messeges have a different image.

Way I have app set up:

All data on MySQL dataBase..... TabBar calls get data, parse and load into TableViews.

That's it really. I just would like the tableView to reload instantanious when the user clicks one of the buttons in detailView. NOTE: clicking buttons in detail View actually changes existing lines in mySQL dataBase and may need to make another call to server to request new array?....That's fine, I suppose, but can't get it to work with viewWillAppear...

I tried to implement:


-(void)viewWillAppear{
[myTableView reloadData];
}


Error: myTableView undeclared.....

Do I need to assign myTableView as a property perhaps? I have read up a bit, and can't figure out the solution.
If you are able to help....I would appreciate any feedback. I can insert more code if it would help anyone who thinks they might have the answer. Thanks again.



CocoaPuffs
May 3, 2009, 06:24 PM
If you can't figure out what the error message means, you have a lot more problems than reloading the data.

To throw you a bone, table view is to be used as an ivar.

jjgraz
May 3, 2009, 06:31 PM
right. This gets rid of error.


-(void)viewWillAppear{
[self.tableView reloadData];
}


However, the tableView still doesn't reload the data. Should I be making another call to server to fetch a new array as the array data has changed?

jjgraz
May 3, 2009, 06:57 PM
I know now that the modification of Cell is taking place. Because when i go to detailView....I click Delete entry......then when going back to parent, app crashes when I try to click the cell again. Thus, the data is gone....It's just not updating the cell to remove the entry......Any thoughts on that?

PhoneyDeveloper
May 4, 2009, 09:18 AM
Obviously you have to update your data source. If you have a database you have some kind of data structure that is used in cellForRowAtIndexPath to populate the rows of your table. You need to update that data structure.

You can do this update every time that viewWillAppear is called or you can explicitly do it when the detail view is closing. Either send a NSNotification from your detail view to the table view controller telling it to refresh itself or use a pointer to the table view controller in the detail view controller to tell it to refresh.

jjgraz
May 4, 2009, 02:12 PM
So my data source is the following:


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

Blt *aBlt = [appDelegate.blts objectAtIndex:indexPath.row];
}


Because I a TabBar which calls the server each time the Tab is selected, I know the data is updated. I logged in debugger, and can see that the data has
been changed after returning to tableView from DetailView........The data in cell isn't changing though.

in TableViewController - ViewWillAppear I have:

-(void)viewWillAppear{
[self.tableView reloadData];
}


How do I tell it to update the cells with new Blt array?

PhoneyDeveloper
May 4, 2009, 06:52 PM
Is your viewWillAppear method being called?

After reloadData is your cellForRowAtIndexPath: being called? If so are you setting the contents of the cells to be the new data?

If you are setting the contents of the cells correctly to the new data but it isn't showing up in the table then you need to show us your code for cellForRowAtIndexPath:

jjgraz
May 4, 2009, 10:51 PM
Finally Got it! Your questions helped me analyze the problem correctly.....viewWillAppear was being called, cellForRowAtIndexPath was being called, new data was being set.......and then I realized in my cellForRowAtIndexPath Code, I had the if statement, if cell == nil ,.....but I didn't have an else statement...So obviously the cells which already had data didn't know how to act....Doh.........Thanks for taking time to help.

PhoneyDeveloper
May 5, 2009, 08:29 AM
Typically there is no else clause to the if (cell == nil) code in cellForRowAtIndexPath. If you don't get back a queued cell then you build a new cell. After that you set all the properties of the cell. You set all the properties of the cell regardless of whether it's a new cell or an old one.

jjgraz
May 5, 2009, 12:37 PM
Please see code below. As of now it works fine like this. Although I'm sure there is a cleaner way to write this.




- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

static NSString *CellIdentifier = @"Cell";
static NSInteger titleTag = 1;
static NSInteger authorTag = 2;

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];

CGRect frame;
frame.origin.x = 10;
frame.origin.y = 5;
frame.size.height = 15;
frame.size.width = 150;

CGRect frame2;
frame2.origin.x = 10;
frame2.origin.y = 5;
frame2.size.height = 35;
frame2.size.width = 60;

frame.origin.x += 40;
UILabel *titleLabel = [[UILabel alloc] initWithFrame:frame];
titleLabel.font = [UIFont boldSystemFontOfSize:16];
titleLabel.tag = titleTag;

[cell.contentView addSubview:titleLabel];
[titleLabel release];

frame.origin.y += 18;
UILabel *authorLabel = [[UILabel alloc] initWithFrame:frame];
authorLabel.font = [UIFont systemFontOfSize:10];
authorLabel.tag = authorTag;
[cell.contentView addSubview:authorLabel];
[authorLabel release];

frame2.origin.x += 225;
frame2.origin.y +=2;
UILabel *bltLabel = [[UILabel alloc] initWithFrame:frame2];
bltLabel.font = [UIFont boldSystemFontOfSize:16];
bltLabel.tag = authorTag;
[cell.contentView addSubview:bltLabel];
[bltLabel release];

Blt *aBlt = [appDelegate.blts objectAtIndex:indexPath.row];

bltLabel.text = aBlt.amount;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;


if ([[NSString stringWithFormat:aBlt.status] isEqualToString: @"A"]) {

UIImage *image = [UIImage imageNamed:@"image1.png"];
cell.image = image;

}

else if ([[NSString stringWithFormat:aBlt.status] isEqualToString: @"B"]){

UIImage *image = [UIImage imageNamed:@"image2.png"];
cell.image = image;
}
else {

UIImage *image = [UIImage imageNamed:@"image3.png"];
cell.image = image;
}

authorLabel.text = aBlt.date;
titleLabel.text = aBlt.firstname;


}
else {
cell = nil;
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];

CGRect frame;
frame.origin.x = 10;
frame.origin.y = 5;
frame.size.height = 15;
frame.size.width = 150;

CGRect frame2;
frame2.origin.x = 10;
frame2.origin.y = 5;
frame2.size.height = 35;
frame2.size.width = 60;

frame.origin.x += 40;
UILabel *titleLabel = [[UILabel alloc] initWithFrame:frame];
titleLabel.font = [UIFont boldSystemFontOfSize:16];
titleLabel.tag = titleTag;

[cell.contentView addSubview:titleLabel];
[titleLabel release];

frame.origin.y += 18;
UILabel *authorLabel = [[UILabel alloc] initWithFrame:frame];
authorLabel.font = [UIFont systemFontOfSize:10];
authorLabel.tag = authorTag;
[cell.contentView addSubview:authorLabel];
[authorLabel release];

frame2.origin.x += 225;
frame2.origin.y +=2;
UILabel *bltLabel = [[UILabel alloc] initWithFrame:frame2];
bltLabel.font = [UIFont boldSystemFontOfSize:16];
bltLabel.tag = authorTag;
[cell.contentView addSubview:bltLabel];
[bltLabel release];

Blt *aBlt = [appDelegate.blts objectAtIndex:indexPath.row];

bltLabel.text = aBlt.amount;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;

if ([[NSString stringWithFormat:aBlt.status] isEqualToString: @"A"]) {

UIImage *image = [UIImage imageNamed:@"image1.png"];
cell.image = image;

}

else if ([[NSString stringWithFormat:aBlt.status] isEqualToString: @"B"]){

UIImage *image = [UIImage imageNamed:@"image2.png"];
cell.image = image;
}
else {

UIImage *image = [UIImage imageNamed:@"image3.png"];
cell.image = image;
}
authorLabel.text = aBlt.date;
titleLabel.text = aBlt.firstname;
}
return cell;
}


So I'm basically saying, If nil do this, else, make it nil, and do same.

PhoneyDeveloper
May 5, 2009, 12:58 PM
No that's not how it's done. You're just ignoring the queued cells.

It should be approximately like this:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

static NSString *CellIdentifier = @"Cell";
static NSInteger titleTag = 1;
static NSInteger authorTag = 2;

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
// Use CGRectMake here, it's more compact
CGRect frame;
frame.origin.x = 10;
frame.origin.y = 5;
frame.size.height = 15;
frame.size.width = 150;

CGRect frame2;
frame2.origin.x = 10;
frame2.origin.y = 5;
frame2.size.height = 35;
frame2.size.width = 60;

frame.origin.x += 40;
UILabel *titleLabel = [[UILabel alloc] initWithFrame:frame];
titleLabel.font = [UIFont boldSystemFontOfSize:16];
titleLabel.tag = titleTag;

[cell.contentView addSubview:titleLabel];
[titleLabel release];

frame.origin.y += 18;
UILabel *authorLabel = [[UILabel alloc] initWithFrame:frame];
authorLabel.font = [UIFont systemFontOfSize:10];
authorLabel.tag = authorTag;
[cell.contentView addSubview:authorLabel];
[authorLabel release];

frame2.origin.x += 225;
frame2.origin.y +=2;
UILabel *bltLabel = [[UILabel alloc] initWithFrame:frame2];
bltLabel.font = [UIFont boldSystemFontOfSize:16];
bltLabel.tag = authorTag;
[cell.contentView addSubview:bltLabel];
[bltLabel release];
}

Blt *aBlt = [appDelegate.blts objectAtIndex:indexPath.row];

UILabel* bltLabel = (UILabel *)[cell.contentView viewWithTag:BLTLabel_TAG];
UILabel* authorLabel = (UILabel *)[cell.contentView viewWithTag: authorTag];
UILabel* titleLabel = (UILabel *)[cell.contentView viewWithTag: titleTag];

bltLabel.text = aBlt.amount;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;

if ([[NSString stringWithFormat:aBlt.status] isEqualToString: @"A"]) {

UIImage *image = [UIImage imageNamed:@"image1.png"];
cell.image = image;

}
else if ([[NSString stringWithFormat:aBlt.status] isEqualToString: @"B"]){

UIImage *image = [UIImage imageNamed:@"image2.png"];
cell.image = image;
}
else {

UIImage *image = [UIImage imageNamed:@"image3.png"];
cell.image = image;
}

authorLabel.text = aBlt.date;
titleLabel.text = aBlt.firstname;

return cell;
}

jjgraz
May 5, 2009, 03:09 PM
That code works perfect, and looks pretty. I really appreciate it. Just so I'm clear,you are dealing with queued cells by creating the new instances of labels following if statement so the queued cells can be dealt with accordingly?



UILabel* bltLabel = (UILabel *)[cell.contentView viewWithTag:BLTLabel_TAG];
UILabel* authorLabel = (UILabel *)[cell.contentView viewWithTag: authorTag];
UILabel* titleLabel = (UILabel *)[cell.contentView viewWithTag: titleTag];

********more code*****


Table understands how to redraw queued cells if not nill.

Give a mouse a crum, he's gonna want a cookie...............I have one more question in the neighborhood of this topic. Please do not feel obligated to address it, your help has already made a huge impact in my learning curve.

I'm trying to set Badges for the cells which are new or unread. I can set badges to an arbitrary number or word using:


self.tabBarItem.badgeValue = @"5";


How is it set for newly created cells?

dejo
May 5, 2009, 03:57 PM
I'm trying to set Badges for the cells which are new or unread. I can set badges to an arbitrary number or word using:


self.tabBarItem.badgeValue = @"5";


How is it set for newly created cells?
You can't set badge values for UITableViewCells, only UITabBarItems.

PhoneyDeveloper
May 5, 2009, 04:14 PM
That code works perfect, and looks pretty. I really appreciate it. Just so I'm clear,you are dealing with queued cells by creating the new instances of labels following if statement so the queued cells can be dealt with accordingly?


Actually no. The whole point of writing the code the way I showed is that the cell and its contents are only created one time. After that if the cell exists its contents are just set. There's no need to create any subviews again. The code I showed gets the existing subviews by identifying them with their tags. Look up viewWithTag.

As mentioned, cells don't have badges. You can set an image. Is that what you want? There's no built in way to create an image from arbitrary text but it's not really hard to do.

jjgraz
May 5, 2009, 04:43 PM
I wasn't clear. I do want to set the badge Value for UITabBarItem. Just like a typical mail application which shows the badge for new messeges. Within my TableView (inbox), I have a read messages mixed with New incoming messages and need the badge to show the user a new message has arrived.

I already have images within cells working properly.....Basically, just looks at a particular string:

if ([[NSString stringWithFormat:aBlt.status] isEqualToString: @"A"]) {

UIImage *image = [UIImage imageNamed:@"image1.png"];
cell.image = image;

}


Thank you

dejo
May 5, 2009, 05:25 PM
I wasn't clear. I do want to set the badge Value for UITabBarItem. Just like a typical mail application which shows the badge for new messeges. Within my TableView (inbox), I have a read messages mixed with New incoming messages and need the badge to show the user a new message has arrived.
Then yes, assuming that tabBarItem is set accordingly, using the code from above to set the badgeValue should be ok.

jjgraz
May 5, 2009, 06:34 PM
Yes, but I don't want the badge to read 5, (as shown below), I want the badge to represent the number of new messeges there are. So I'm not quite understanding how to implement this. self.tabBarItem.badgeValue = ?.
I appreciate it.


self.tabBarItem.badgeValue = @"5";

dejo
May 5, 2009, 07:15 PM
Now would be a good time to do some research on converting an int (or NSNumber) into a string (NSString). That should get you started.

jjgraz
May 5, 2009, 07:22 PM
Thank you. I will do just that.

jjgraz
May 7, 2009, 04:25 PM
I got the badges working correctly. It looks something like:

NSString *temp = [[NSString alloc] initWithFormat: @"%d", [appDelegate.blts count]];

self.tabBarItem.badgeValue = temp;
[temp release];



blts count is an NSArray coming from my server(mySQL).
Right now NSArray blts is array of all messeges for user, so this means the badges information reflects total of cells within the TableView(not just unread).

I was wondering if anyone might be able to suggest a good method for pulling unread only.

Is there a way to filter an array based on a string in Xcode?

My thoughts are: Creating a column in MySQL database which just says read/unread....So when array arrives at TableView.....only messages with string equal to unread are used in badging. Then when a user didSelectCell
another call to server would modify database column from unread to read...thus updating the badge correctly......If this sounds completely wrong, please let me know if there is a better option to look into. I appreciate it very much.