iOS Refresh button in View Controller Nav: reloading all tableViewCells created from parsed JSON when clicked

10,400

You need to call the reload method.

[self.tableView reloadData];

This will fire the dataSource and delegate events an will refresh the UITableView.

You can find more info in the UITableView Class Reference:

Call this method to reload all the data that is used to construct the table, including cells, section headers and footers, index arrays, and so on. For efficiency, the table view redisplays only those rows that are visible.

Share:
10,400
Pat
Author by

Pat

Updated on July 01, 2022

Comments

  • Pat
    Pat almost 2 years

    I've got a fairly important conceptual issue that many people have asked about, but there isn't a readily available clear answer to be found by searching.

    My application is simple: Several rows of TableViewCells populated with data from a parsed JSON feed. When a cell is clicked on, that cell's info is passed to a SecondViewController and displayed. The JSON feed is also stored to a .plist and in the case that the internet is not available, the TableViewCells are populated from the .plist.

    This is all working great.

    However, the last thing I need is a refresh button at the top of my FirstViewController to refresh the JSON feed, and all of the cells in the table with the new data from the new variables. However, I've encountered an issue with implementing this:

    My original JSON call, and variables to populate the cells are located in the ViewDidLoad method. When the view loads, these variables are "set" and don't refresh. Further, I can move the JSON call and variables into viewWillLoad - which will refresh the table each time after clicking on a cell, and then clicking "back" to the firstViewController -- this will update the JSON and cells successfully, however it does impact the speed and makes the view controller "pause" when going back to the MainViewController, which makes calling my original JSON and setting my variables in viewWillLoad an unviable option.

    I have created a reload button in ViewDidLoad, which is linked to an IBAction method "refresh":

    Create Button Programitically in ViewDidLoad:

    // Reload issues button
    UIBarButtonItem *button = [[UIBarButtonItem alloc]
                               initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh
                               target:self
                               action:@selector(refresh:)];
    self.navigationItem.rightBarButtonItem = button;
    [button release];
    

    Action Method it's linked to:

    - (IBAction)refresh:(id)sender {
    
        myRawJson = [[NSString alloc] initWithContentsOfURL:[NSURL  
                                      URLWithString:@"http://www.yoursite.com/json.JSON"]  
                                      encoding:NSUTF8StringEncoding 
                                      error:nil];
    
        SBJsonParser *parser = [[SBJsonParser alloc] init];
        NSDictionary * myParsedJson = [parser objectWithString:myRawJson error:NULL];
    
    // New updated dictionary built from refreshed JSON
        allLetterContents = [myParsedJson objectForKey:@"nodes"];
    
    // Log the new refreshed JSON
        NSLog(@"You clicked refresh. Your new JSON is %@", myRawJson);
    
        //Maybe use the notification center?? But don't know how to implement.
        //[[NSNotificationCenter defaultCenter] addObserver:self 
                                                selector:@selector(refreshView:) 
                                                name:@"refreshView" object:nil];
        //[[NSNotificationCenter defaultCenter] postNotificationName:@"refreshView" 
                                                object:nil];
    
        }
    
        [self.tableView reloadRowsAtIndexPaths:[self.tableView indexPathsForVisibleRows] 
                         withRowAnimation:UITableViewRowAnimationNone];
    
        [myRawJson release];
    }
    

    In the code above you can see that I'm re-calling the JSON each time the button is clicked and logging a message to console with the new JSON. This is working. I've even re-built a dictionary which is successfully adding the new content.

    My question is: How can I make the tableViewCells "refresh" with this new data as well? Can I just make the button re-load the entire view controller - so it would call ViewDidLoad again? Do I need to re-think my apps structure, or move my original variables out of viewDidLoad?

    I've been reading some posts on the NSNotificationCenter, but the implementation of this still baffles me, as I'm fairly new to iOS development.

    Thanks~


    Update:


    It's still not updating. Here is my full refresh button code with [self.tableView reloadData]; called at the end of my IBAction.

        - (IBAction)refresh:(id)sender {
            [DSBezelActivityView newActivityViewForView:        
                             self.navigationController.navigationBar.superview     
                             withLabel:@"Loading Feed..." width:160];
    
            myRawJson = [[NSString alloc] initWithContentsOfURL:[NSURL 
                         URLWithString:@"http://site.com/mobile.JSON"] 
                         encoding:NSUTF8StringEncoding 
                         error:nil];
    
            SBJsonParser *parser = [[SBJsonParser alloc] init];
            NSDictionary * myParsedJson = [parser objectWithString:myRawJson error:NULL];
            allLetterContents = [myParsedJson objectForKey:@"nodes"];
    
            BOOL isEmpty = ([myParsedJson count] == 0);
    
            if (isEmpty) {
                NSString *refreshErrorMessage = [NSString 
    stringWithFormat:@"An internet or network connection is required."];
                UIAlertView *alert = [[UIAlertView alloc] 
                                     initWithTitle:@"Alert" 
                                     message: refreshErrorMessage 
                                     delegate:self 
                                     cancelButtonTitle:@"Close" 
                                     otherButtonTitles:nil];
                [alert show];
                [alert release];
    
                allLetterContents = [NSMutableDictionary 
                                    dictionaryWithContentsOfFile:[self saveFilePath]];
                //NSLog(@"allLetterContents from file: %@", allLetterContents);
    
            } else {
    
            NSLog(@"Your new allLetterContents is %@",  allLetterContents);
    
              // Fast enumeration through the allLetterContents NSMutableDictionary
              for (NSMutableDictionary * key in allLetterContents) {
                NSDictionary *node = [key objectForKey:@"node"];
                NSMutableString *contentTitle = [node objectForKey:@"title"];        
                NSMutableString *contentNid = [node objectForKey:@"nid"];
                NSMutableString *contentBody = [node objectForKey:@"body"];
                // Add each Title and Nid to specific arrays
                //[self.contentTitleArray addObject:contentTitle];
                [self.contentTitleArray addObject:[[contentTitle 
                                         stringByReplacingOccurrencesOfString:@"&" 
                                         withString:@"&"] mutableCopy]];
                [self.contentNidArray addObject:contentNid];
                [self.contentBodyArray addObject:contentBody];
              }
    
            }
    
            [self.tableView reloadData];
    
            [DSBezelActivityView removeViewAnimated:YES];
            [myRawJson release];
        }
    

    I'm configuring the cell at cellForRowAtIndexPath (Updated: Posted entire method):

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        static NSString *CellIdentifier = @"Cell";
    
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
        if (cell == nil) {
            cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
            if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
                cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
            }
        }
    
        // Configure the cell.
        cell.textLabel.text = [self.contentTitleArray objectAtIndex: [indexPath row]];
        cell.detailTextLabel.text = [self.contentNidArray objectAtIndex: [indexPath row]];
        return cell;
    }
    

    Setting it on didSelectRowAtIndexPath:

    self.detailViewController.currentNodeTitle = [contentTitleArray 
                                                 objectAtIndex:indexPath.row];
    self.detailViewController.currentNodeNid= [contentNidArray 
                                              objectAtIndex:indexPath.row];
    self.detailViewController.currentNodeBody = [contentBodyArray 
                                                objectAtIndex:indexPath.row];
    

    So when clicking my refresh button the table should* refresh with the new json, but does not.. Am I missing a step?

    enter image description here

    Additionally this may not be important, but I'm changing the colors for every other row with:

    // Customize the appearance of table view cells.
    -(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
        if (indexPath.row % 2)
        {
            [cell setBackgroundColor:[UIColor colorWithRed:221.0/255.0 green:238.0/255.0 blue:255.0/255.0 alpha:1]];
            cell.textLabel.textColor = [UIColor colorWithRed:2.0/255.0 green:41.0/255.0 blue:117.0/255.0 alpha:1];
            cell.detailTextLabel.textColor = [UIColor colorWithRed:2.0/255.0 green:41.0/255.0 blue:117.0/255.0 alpha:1];
    
        }    else [cell setBackgroundColor:[UIColor clearColor]];
    }
    

    Update

    enter image description here

  • Pat
    Pat over 12 years
    Well this is what many other posts have said, but when I add [self.tableView reloadData]; to the end of - (IBAction)refresh:(id)sender, it has no effect. Any other ideas? Or maybe I am just calling it in the wrong place?
  • Pat
    Pat over 12 years
    I've updated my post to include my IBAction code and some more info. Perhaps I'm missing some code? I can verify that the JSON has changed by running the app, then updating the JSON source, and when I click the "refresh" button my NSLog shows that the refreshed button outputs new content, but the cells don't update.