UICollectionView doesn't update immediately when calling reloadData, but randomly after 30-60 seconds

17,263

Solution 1

This is a classic symptom of calling UIKit methods from a background thread. If you view the -[SLRequest performRequestWithHandler:] documentation, it says the handler makes no guarantee of which thread it will be run on.

Wrap your call to reloadData in a block and pass this to dispatch_async(); also pass dispatch_get_main_queue() as the queue argument.

Solution 2

You need to dispatch the update to the main thread:

 dispatch_async(dispatch_get_main_queue(), ^{
    [self.photoStreamCollectionView reloadData];
  });

or in Swift:

dispatch_async(dispatch_get_main_queue(), {
    self.photoStreamCollectionView.reloadData()
})

Solution 3

Apple say:You should not call this method in the middle of animation blocks where items are being inserted or deleted. Insertions and deletions automatically cause the table’s data to be updated appropriately.

In face: You should not call this method in the middle of any animation (include UICollectionView in the scrolling).

so, you can:

[self.collectionView setContentOffset:CGPointZero animated:NO];
[self.collectionView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO];

or mark sure not any animation, and then call reloadData; or

[self.collectionView performBatchUpdates:^{
//insert, delete, reload, or move operations
} completion:nil];
Share:
17,263
nullfox
Author by

nullfox

Updated on September 15, 2022

Comments

  • nullfox
    nullfox over 1 year

    As the title implies, my UICollectionView doesn't update and display the cells immediately after calling reloadData. Instead, it seems to eventually update my collection view after 30-60 seconds. My setup is as follows:

    UICollectionView added to view controller in Storyboard with both delegate and dataSource setup for the view controller and standard outlet setup numberOfSectionsInRow & cellForItemAtIndexPath are both implemented and reference the prototyped cell and the imageView inside of it

    Here is the code that goes to Twitter, get's a timeline, assigns it to a variable, reloads a table view with the tweets and then goes through the tweets to find photos and reloads the collection view with those items.

    Even if I comment out the code to display the image, it still doesn't change anything.

    SLRequest *timelineRequest = [SLRequest requestForServiceType:SLServiceTypeTwitter requestMethod:SLRequestMethodGET URL:timelineURL parameters:timelineParams];
    [timelineRequest performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
        if(responseData) {
            JSONDecoder *decoder = [[JSONDecoder alloc] init];
    
            NSArray *timeline = [decoder objectWithData:responseData];
    
            [self setTwitterTableData:timeline];
    
            for(NSDictionary *tweet in [self twitterTableData]) {
                if(![tweet valueForKeyPath:@"entities.media"]) { continue; }
    
                for(NSDictionary *photo in [[tweet objectForKey:@"entities"] objectForKey:@"media"]) {
                    [[self photoStreamArray] addObject:[NSDictionary dictionaryWithObjectsAndKeys:
                                                        [photo objectForKey:@"media_url"], @"url",
                                                        [NSValue valueWithCGSize:CGSizeMake([[photo valueForKeyPath:@"sizes.large.w"] floatValue], [[photo valueForKeyPath:@"sizes.large.h"] floatValue])], @"size"
                                                        , nil]];
                }
            }
    
            [[self photoStreamCollectionView] reloadData];
        }
    }];
    
  • nullfox
    nullfox about 11 years
    You win! Wrapping the code exactly as you said fixed the issue. Is there a fundamental difference between UITableView and UICollectionView that would let reloadData work on UITableView but not UICollectionView?
  • Carl Veazey
    Carl Veazey about 11 years
    @nullfox glad it worked! I'm not aware of any difference but if there is one it's likely implementation details that shoudln't be relied on. The only course of action is to make sure messages sent to any UIKit object are sent on the main thread.
  • RyJ
    RyJ almost 10 years
    HOURS of debugging solved with your simple fix! Same problem relates to UITableView incidentally. Thank you!
  • Carl Veazey
    Carl Veazey almost 10 years
    @RyJ so glad to help!