UICollectionView 在调用 reloadData 时不会立即更新,而是在 30-60 秒后随机更新

Posted

技术标签:

【中文标题】UICollectionView 在调用 reloadData 时不会立即更新,而是在 30-60 秒后随机更新【英文标题】:UICollectionView doesn't update immediately when calling reloadData, but randomly after 30-60 seconds 【发布时间】:2013-02-11 00:37:14 【问题描述】:

正如标题所暗示的,我的UICollectionView 在调用reloadData 后不会立即更新和显示单元格。相反,它似乎最终会在 30-60 秒后更新我的收藏视图。我的设置如下:

UICollectionView 添加到 Storyboard 中的视图控制器,同时为视图控制器和标准插座设置设置了 delegatedataSource numberOfSectionsInRowcellForItemAtIndexPath 都已实现并引用原型单元和其中的 imageView

这是转到 Twitter 的代码,获取时间线,将其分配给变量,重新加载带有推文的表格视图,然后通过推文查找照片并重新加载带有这些项目的集合视图。

即使我注释掉显示图像的代码,它仍然没有改变任何东西。

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];
    
];

【问题讨论】:

你确定这不仅仅是因为在请求完成之前你没有调用 -reloadData 吗? (这需要时间)。 【参考方案1】:

这是从后台线程调用 UIKit 方法的典型症状。如果您查看-[SLRequest performRequestWithHandler:] documentation,它表示处理程序不保证它将在哪个线程上运行。

将您对reloadData 的调用封装在一个块中并将其传递给dispatch_async();还将dispatch_get_main_queue() 作为队列参数传递。

【讨论】:

你赢了!完全按照您所说的包装代码解决了这个问题。 UITableView 和 UICollectionView 之间是否存在根本区别,可以让 reloadData 在 UITableView 而不是 UICollectionView 上工作? @nullfox 很高兴它成功了!我不知道有什么区别,但如果有的话,很可能是不应该依赖的实现细节。唯一的做法是确保发送到任何 UIKit 对象的消息都在主线程上发送。 用你的简单修复解决了几个小时的调试问题!顺便说一句,同样的问题与 UITableView 有关。谢谢! @RyJ 很高兴为您提供帮助! @CarlVeazey 感谢提示“这是从后台线程调用 UIKit 方法的典型症状。”我正在从 NSNotificationCenter 重新加载 UICollectionView,它表现得很愚蠢。在 dispatch_async 中包装 reload 解决了它。【参考方案2】:

您需要将更新分派到主线程:

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

或在 Swift 中:

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

【讨论】:

【参考方案3】:

Apple 说:您不应该在插入或删除项目的动画块中间调用此方法。插入和删除会自动导致表的数据得到适当的更新。

面对:你不应该在任何动画中间调用这个方法(包括 UICollectionView 在滚动)。

所以,你可以:

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

或者标记确定没有任何动画,然后调用reloadData; 或

[self.collectionView performBatchUpdates:^
//insert, delete, reload, or move operations
 completion:nil];

【讨论】:

以上是关于UICollectionView 在调用 reloadData 时不会立即更新,而是在 30-60 秒后随机更新的主要内容,如果未能解决你的问题,请参考以下文章

UICollectionView 在 UICollectionViewCells 上调用 setNeedsDisplay

同时在多个 UICollectionView 上调用 reloadData

在 UICollectionView 上调用 reloadData 后 contentSize 未更新

无法在 Swift 3 中调用非函数类型“UICollectionView”的值

未调用 UICollectionView 内部 UITableView 的委托方法

UICollectionView 委托方法没有被正确调用