Reload the table after user makes a change.

Discussion in 'iPhone/iPad Programming' started by jjgraz, May 3, 2009.

  1. macrumors regular

    jjgraz

    Joined:
    Feb 13, 2009
    #1
    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:

    Code:
    -(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.
     
  2. macrumors 68010

    Joined:
    Aug 23, 2008
    #2
    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.
     
  3. thread starter macrumors regular

    jjgraz

    Joined:
    Feb 13, 2009
    #3
    right. This gets rid of error.

    Code:
    -(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?
     
  4. thread starter macrumors regular

    jjgraz

    Joined:
    Feb 13, 2009
    #4
    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?
     
  5. macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #5
    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.
     
  6. thread starter macrumors regular

    jjgraz

    Joined:
    Feb 13, 2009
    #6
    So my data source is the following:

    Code:
    - (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:
    Code:
    -(void)viewWillAppear{	
    	[self.tableView reloadData];	
    }
      
    How do I tell it to update the cells with new Blt array?
     
  7. macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #7
    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:
     
  8. thread starter macrumors regular

    jjgraz

    Joined:
    Feb 13, 2009
    #8
    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.
     
  9. macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #9
    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.
     
  10. thread starter macrumors regular

    jjgraz

    Joined:
    Feb 13, 2009
    #10
    Please see code below. As of now it works fine like this. Although I'm sure there is a cleaner way to write this.


    Code:
     
    
    - (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.
     
  11. macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #11
    No that's not how it's done. You're just ignoring the queued cells.

    It should be approximately like this:

    Code:
    - (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;
    }
     
  12. thread starter macrumors regular

    jjgraz

    Joined:
    Feb 13, 2009
    #12
    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?

    Code:
    
            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:

    Code:
    self.tabBarItem.badgeValue = @"5"; 
    
    How is it set for newly created cells?
     
  13. Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #13
    You can't set badge values for UITableViewCells, only UITabBarItems.
     
  14. macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #14
    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.
     
  15. thread starter macrumors regular

    jjgraz

    Joined:
    Feb 13, 2009
    #15
    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:
    Code:
    if ([[NSString stringWithFormat:aBlt.status] isEqualToString: @"A"]) {
    		
    		UIImage *image = [UIImage imageNamed:@"image1.png"];
    		cell.image = image;
    		
    	}
    
    Thank you
     
  16. Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #16
    Then yes, assuming that tabBarItem is set accordingly, using the code from above to set the badgeValue should be ok.
     
  17. thread starter macrumors regular

    jjgraz

    Joined:
    Feb 13, 2009
    #17
    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.

    Code:
    self.tabBarItem.badgeValue = @"5";
    
     
  18. Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #18
    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.
     
  19. thread starter macrumors regular

    jjgraz

    Joined:
    Feb 13, 2009
    #19
    Thank you. I will do just that.
     
  20. thread starter macrumors regular

    jjgraz

    Joined:
    Feb 13, 2009
    #20
    I got the badges working correctly. It looks something like:
    Code:
    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.
     

Share This Page