UICollectionView doesn't update immediately when calling reloadData, but randomly after 30-60 seconds
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];
nullfox
Updated on September 15, 2022Comments
-
nullfox over 1 year
As the title implies, my
UICollectionView
doesn't update and display the cells immediately after callingreloadData
. 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 bothdelegate
anddataSource
setup for the view controller and standard outlet setupnumberOfSectionsInRow
&cellForItemAtIndexPath
are both implemented and reference the prototyped cell and theimageView
inside of itHere 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 about 11 yearsYou 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 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 almost 10 yearsHOURS of debugging solved with your simple fix! Same problem relates to UITableView incidentally. Thank you!
-
Carl Veazey almost 10 years@RyJ so glad to help!