0

I'm fetching the value of my UILabel from Rotten Tomatoes API and I want my text inside my custom cell to update whenever the value has been fetched already. I tried doing that by reloading my UITableView but it goes on a loop.

Here's my code:

if (ratingTomatoLabel.text == nil)
    {
        NSLog(@"   Nil");

        NSString *stringWithNoSpaces = [movieTitle.text stringByReplacingOccurrencesOfString:@" " withString:@"%20"];
        NSString *rottenTomatoRatingString = [NSString stringWithFormat:@"%@%@%@", @"http://api.rottentomatoes.com/api/public/v1.0/movies.json?apikey=6844abgw34rfjukyyvzbzggz&q=", stringWithNoSpaces, @"&page_limit=1"];
        NSLog(@"   Rotten URL: %@", rottenTomatoRatingString);
        NSURL *rottenUrl = [[NSURL alloc] initWithString:rottenTomatoRatingString];
        NSURLRequest *rottenRequest = [[NSURLRequest alloc] initWithURL:rottenUrl];

        AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:rottenRequest success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
            NSLog(@"      3");
            self.testDict = [JSON objectForKey:@"movies"];
        } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
            NSLog(@"Request Failed with Error: %@, %@", error, error.userInfo);
        }];

        [operation start];

        NSLog(@"   %@", ratingTomatoLabel.text);
        ratingTomatoLabel.text = @"...";
    }
    else if ([ratingTomatoLabel.text isEqualToString:@""])
    {
        NSLog(@"   isEqualToString");
        // Do nothing
    }
    else
    {
        NSLog(@"   else");
    }

    return tableCell;

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    NSLog(@"      fetched!");

    if ([ratingTomatoLabel.text isEqualToString:@"..."])
    {
        NSLog(@"      2nd nil");
        NSDictionary *dict = [self.testDict valueForKey:@"ratings"];
        self.criticsScoreString = [NSString stringWithFormat:@"%@", [dict valueForKey:@"critics_score"]];
        self.criticsScoreString = [self.criticsScoreString stringByReplacingOccurrencesOfString:@" " withString:@""];
        self.criticsScoreString = [self.criticsScoreString stringByReplacingOccurrencesOfString:@"(" withString:@""];
        self.criticsScoreString = [self.criticsScoreString stringByReplacingOccurrencesOfString:@")" withString:@""];
        self.criticsScoreString = [NSString stringWithFormat:@"%@%@", self.criticsScoreString, @"%"];

        ratingTomatoLabel.text = self.criticsScoreString;
        NSLog(@"      %@", ratingTomatoLabel.text);
    }
    else
    {
        NSLog(@"      2nd not nil");
        NSLog(@"      %@", ratingTomatoLabel.text);
        // Do nothing
    }
}

If I added the code [self.myTableView reloadData]; after setting the value in my text, it goes on a loop. What's the best way to do this? Thanks!

UPDATE: Included updated code and another method. Also, my ratingTomatoLabel always goes nil when it's not displayed.

jaytrixz
  • 4,059
  • 7
  • 38
  • 57

2 Answers2

0

Jaytrix

With the AFNetworking calls happening asynchronously, consider using some sort of notification to tell the main thread (UI) when work is complete or an error occurs.

Frank

Frank C.
  • 7,758
  • 4
  • 35
  • 45
0

You should use KVO (Key-value observing) to detect when there are changes to your dictionary or array - in this case it seems self.testDict.

When you receive this notification, use UITableView's -visibleCells method to update only the visible cells - the others will obviously take on their new value when their cell is recycled using -tableView:cellForRowAtIndexPath:.

What's required for KVO: Registering/deregistering when views load/change and setting the variable you wish to observe...

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if([keyPath isEqual:@"testDict"])
    {
        NSLog(@"KVO change: %@", change);
        NSArray *visibleCells = [self.myTableView visibleCells];
        for(UITableViewCell *cell in visibleCells)
        {
            if(/*cell matches the one I'm targeting OR just update regardless*/)
                // assign value to UILabel
        }
    }
}

// Call this from -viewDidLoad
- (void)registerAsObserver
{
    [self addObserver:self forKeyPath:@"testDict" options:NSKeyValueObservingOptionNew context:NULL];
}

// Call this from -viewWillDisappear and -viewDidUnload (may not be necessary for -viewDidUnload if already implemented in -viewWillDisappear)
- (void)unregisterAsObserver
{
    [self removeObserver:self forKeyPath:@"testDict"];
}

Lastly, to update the cell(s) that have changed, call the -reloadRowsAtIndexPaths:withRowAnimation: method to have the underlying system refresh the cell.

Alex Smith
  • 468
  • 5
  • 22
  • It's not working. :( In the if statement, I placed the condition `if ([ratingTomatoLabel.text isEqualToString:@""])` since I changed my code to initially display blank if the value isn't fetched yet. – jaytrixz Feb 06 '13 at 02:06
  • It actually works but the label isn't updated. Any idea why it isn't? The method is called but the label changes isn't happening. I verified it by temporarily displaying a UIAlertView with the values inside the method yet the label value doesn't change. – jaytrixz Feb 06 '13 at 03:00
  • `[cell.textLabel setText:updatedValue];` doesn't work? I may need to see your implementation for this. Easiest way for this is to update your question. – Alex Smith Feb 06 '13 at 04:05
  • I just [found this](http://stackoverflow.com/questions/5577401/update-uitableviewcell-without-reload)! `- (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation` I will include it in my original answer. – Alex Smith Feb 06 '13 at 04:10
  • The method's not getting called. – jaytrixz Feb 06 '13 at 05:44