UICollectionView reloadData无效

时间:2017-10-14 15:20:24

标签: ios swift uicollectionview

在获取所使用的数据后,它在viewDidLoad中被调用。 在一些打印调试之后,如果没有更改数据,它看起来像调用所有适当的delegeate方法。如果更改了某些数据,则不会调用cellForItemAt

重新加载整个部分工作正常。但是给了我一个不需要的动画。尝试在之前禁用UIView动画,并在重新加载部分后启用,但仍然给我一点动画。

collectionView.reloadSections(IndexSet(integer: 0)) 

这是我目前使用reloadData()

时的情况

UICollectionViewController是TabBarController的一部分。 我正在使用自定义UICollectionViewCells。数据从CoreData加载。

首次打开标签,其工作正常。 在另一个选项卡中更新收藏夹项目并返回此collectionView后,它未更新。但是,如果我选择另一个标签,并返回到此标签,则更新。

var favorites = [Item]()


override func viewWillAppear(_ animated: Bool) {

    collectionView!.register(UINib.init(nibName: reuseIdentifier, bundle: nil), forCellWithReuseIdentifier: reuseIdentifier)

    if let flowLayout = collectionView!.collectionViewLayout as? UICollectionViewFlowLayout {
        flowLayout.estimatedItemSize = CGSize(width: 1,height: 1)
    }

    loadFavorites()

}


func loadFavorites() {

    do {
        print("Load Favorites")

        let fetch: NSFetchRequest = Item.fetchRequest()
        let predicate = NSPredicate(format: "favorite == %@", NSNumber(value: true))
        fetch.predicate = predicate
        favorites = try managedObjectContext.fetch(fetch)

        if favorites.count > 0 {
            print("Favorites count: \(favorites.count)")
            notification?.removeFromSuperview()
        } else {
            showEmptyFavoritesNotification()
        }

        print("Reload CollectionView")

        collectionView!.reloadData(


    } catch {
        print("Fetching Sections from Core Data failed")
    }
}


override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {

    print("Get number of section, \(favorites.count)")
    if favorites.count > 0 {
        return favorites.count
    } else {
        return 0
    }
}

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    print("Get cell")

    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! SubMenuCell

    let menuItem = favorites[indexPath.row]

    cell.title = menuItem.title
    cell.subtitle = menuItem.subtitle

    return cell
}

控制台打印/记录

启动应用,转到没有收藏夹的CollectionView标签:

Load Favorites
Get number of section, 0
Get number of section, 0
Reload CollectionView
Get number of section, 0

切换选项卡,将Item对象的收藏夹添加并设置为true,然后返回CollectionView选项卡:

Load Favorites
Favorites count: 1
Reload CollectionView
Get number of section, 1

The datamodel has 1 item, reloading CollectonView, cellForRowAtIndex not called?

选择另一个标签,随机选择,然后返回到CollectionView标签,而不更改任何数据。

Load Favorites
Favorites count: 1
Reload CollectionView
Get number of section, 1
Get cell

现在我的项目显示在列表中。您可以从Get Cell中看到cellForItemAt被称为。在最后两次记录之间没有任何变化,只需在标签上单击后退/第四次。

忘了提,但这段代码在模拟器中运行良好。 在读取设备上它只是没有给我任何错误,只是没有显示单元格(或调用cellForItemAt

5 个答案:

答案 0 :(得分:3)

经过一些调试后,当项目减少时出现错误(而不是像我上面尝试的那样增加)。

UICollectionView received layout attributes for a cell with an index path that does not exist

这导致了iOS 10 bug: UICollectionView received layout attributes for a cell with an index path that does not exist

collectionView!.reloadData()
collectionView!.collectionViewLayout.invalidateLayout()
collectionView!.layoutSubviews()

这解决了我的问题。

我正在使用自动调整单元格,但我想这并不能解释为什么cellForItemAt没有被调用。

答案 1 :(得分:2)

好的,也许我可以帮助某人=)

我这样做:

  1. 从API加载数据
  2. 在加载数据后,像这样

    调用DispatchQueue.main.async
        DispatchQueue.main.async {
            self.pointNews = pointNews
        }
    
  3. 在self.pointNews didSet 中,我尝试执行collectionView.reloadData(),但仅当我在didSet中调用DispatchQueue.main.async时,此方法才有效

        DispatchQueue.main.async {
            self.collectionView.reloadData()
        }
    

答案 2 :(得分:1)

在我的情况下,我的collectionview是在stackview中,当添加必要的约束时,我没有做任何约束。

只需检查collectionview的约束。

答案 3 :(得分:0)

发布您的代码。

一种可能性是你正在使用`URLSession并尝试告诉你的集合视图从它的委托方法/完成闭包更新,没有意识到该代码是在后台线程上运行而你不能从背景线程。

答案 4 :(得分:0)

我在调整单元格大小时遇到​​了同样的问题,上述解决方案也可以工作,但是集合视图滚动位置会重置并返回顶部。以下解决方案有助于保持滚动位置

collectionView.reloadData()
let context = collectionView.collectionViewLayout.invalidationContext(forBoundsChange: collectionView.bounds)
context.contentOffsetAdjustment = CGPoint.zero
collectionView.collectionViewLayout.invalidateLayout(with: context)
collectionView.layoutSubviews()