Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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];
    }
}];
like image 857
nullfox Avatar asked Feb 11 '13 00:02

nullfox


3 Answers

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.

like image 122
Carl Veazey Avatar answered Nov 13 '22 20:11

Carl Veazey


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()
})
like image 39
ricardohdz Avatar answered Nov 13 '22 20:11

ricardohdz


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];
like image 27
diong Avatar answered Nov 13 '22 19:11

diong