UICollectionView reloadData() 不会更新集合视图中的单元格

Posted

技术标签:

【中文标题】UICollectionView reloadData() 不会更新集合视图中的单元格【英文标题】:UICollectionView reloadData() does not update cells in the collection view 【发布时间】:2017-02-15 05:50:18 【问题描述】:

这是我想要实现的目标的高级描述; 1. 获取数据 2. 将获取的数据保存在数组对象中 3. 用数组的大小更新collection view

这是我的代码

class ItemcollectionViewController:UICollectionViewController, UICollectionViewDelegateFlowLayout 

  let cellId = "CellId"
  var categories = [Category]()
  let viewOptionVar:ViewOptionBar = 
      let vOV = ViewOptionBar()
      vOV.translatesAutoresizingMaskIntoConstraints = false
      return vOV
  ()

  private func fetchData() 
      let categoryController = CategoryController()
      categoryController.getAllCategory(username: "blah", password: "password") (returnedCategories, error) -> Void in
            if error != nil 
               print(error)
               return
            
            self.categories = returnedCategories!
            print("size of the array is \(self.categories.count)")
            OperationQueue.main.addOperationself.collectionView?.reloadData()
      

  

  override func viewDidLoad() 
    super.viewDidLoad()
    fetchData()
    collectionView?.backgroundColor = UIColor.white
    collectionView?.register(ItemCell.self, forCellWithReuseIdentifier: cellId)
    collectionView?.contentInset = UIEdgeInsetsMake(50, 0, self.view.frame.height, self.view.frame.width)
    collectionView?.scrollIndicatorInsets = UIEdgeInsetsMake(50, 0, 0, self.view.frame.width)
  

  override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int 
    print("in the method \(self.categories.count)")
    return self.categories.count
  

  override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! ItemCell
    cell.category = categories[indexPath.item]
    return cell
  

  func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize 
    return CGSize(width: 111, height: 111)
  

  func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat 
    return 0
  

  private func setupViweOptionBar() 
    view.addSubview(viewOptionVar)
    view.addConstraintsWithFormat(format: "H:|[v0]|", views: viewOptionVar)
    view.addConstraintsWithFormat(format: "V:|[v0(50)]", views: viewOptionVar)
  

在日志中我可以看到以下语句:

在方法0中

数组大小为3

在我的视野中看不到任何单元格。

谁能告诉我我做错了什么? 提前致谢。

编辑 1 现在我在注册自定义单元格后获取数据。但是还是不行

更新代码:

class ItemcollectionViewController:UICollectionViewController, UICollectionViewDelegateFlowLayout 

  let cellId = "CellId"
  var categories = [Category]()
  let viewOptionVar:ViewOptionBar = 
      let vOV = ViewOptionBar()
      vOV.translatesAutoresizingMaskIntoConstraints = false
      return vOV
  ()

  private func fetchData() 
      let categoryController = CategoryController()
      categoryController.getAllCategory(username: "blah", password: "password") (returnedCategories, error) -> Void in
            if error != nil 
               print(error)
               return
            
            self.categories = returnedCategories!
            print("size of the array is \(self.categories.count)")

      

  

  override func viewDidLoad() 
    super.viewDidLoad()
    collectionView?.backgroundColor = UIColor.white
    collectionView?.register(ItemCell.self, forCellWithReuseIdentifier: cellId)
    collectionView?.contentInset = UIEdgeInsetsMake(50, 0, self.view.frame.height, self.view.frame.width)
    collectionView?.scrollIndicatorInsets = UIEdgeInsetsMake(50, 0, 0, self.view.frame.width)
    collectionView?.dataSource = self
    collectionView?.delegate = self
    fetchData()
    DispatchQueue.main.asyncself.collectionView?.reloadData()
  

  override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int 
    print("in the method \(self.categories.count)")
    return self.categories.count
  

  override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! ItemCell
    cell.category = categories[indexPath.item]
    return cell
  

  func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize 
    return CGSize(width: 111, height: 111)
  

  func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat 
    return 0
  

  private func setupViweOptionBar() 
    view.addSubview(viewOptionVar)
    view.addConstraintsWithFormat(format: "H:|[v0]|", views: viewOptionVar)
    view.addConstraintsWithFormat(format: "V:|[v0(50)]", views: viewOptionVar)
  

编辑 2

以下代码是我的查询方法

func getAllCategory(username:String, password:String, callback: @escaping ([Category]?, String?) -> Void)
    var categories = [Category]()
    let fetchCategories = URL(string: userURL + "all")
    URLSession.shared.dataTask(with: fetchCategories!, completionHandler:  (data, response, error) in
        if let err = error 
            print(err)
            return
        
        do 
            let jsonCategoryObj = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! [[String: AnyObject]]
            for categoryDictionary in jsonCategoryObj 
                let category = Category()
                category.categoryId = categoryDictionary["categoryId"] as? String
                category.categoryName = categoryDictionary["categoryName"] as? String
                category.categoryDescription = categoryDictionary["categoryDescription"] as? String
                let categoryRegisteredDateString = categoryDictionary["categoryRegisteredDate"] as? String
                let df = DateFormatter()
                df.dateFormat = self.shapeDateFormat
                let categoryRegisteredDate = df.date(from: categoryRegisteredDateString!)!
                category.categoryRegisteredDate = categoryRegisteredDate

                categories.append(category)

            
            callback(categories, nil)
        catch let jsonError 
            callback(nil, String(describing: jsonError))
        

    ).resume()

仅供参考:我知道我没有使用传递的用户凭据,这只是我的不同查询方法的复制和粘贴错误

【问题讨论】:

你好。你有没有解决这个问题,或者你只是按照我要的方式给了你? 【参考方案1】:

当 DataSource 改变时,reloadData 不会更新视图中已经显示的单元格。重新加载可见项目将完成这项工作。

    self.collectionView.reloadData()
    self.collectionView.performBatchUpdates( [weak self] in
        let visibleItems = self?.collectionView.indexPathsForVisibleItems ?? []
        self?.collectionView.reloadItems(at: visibleItems)
    , completion:  (_) in
    )

【讨论】:

【参考方案2】:

我不确定这是如何解决这个问题的。但我只是添加了

print("size of the array is \(self.categories?.count)")

就在旁边

OperationQueue.main.addOperationself.collectionView?.reloadData()

它神奇地起作用..甚至认为当我回到屏幕上时,它什么也没显示。

我会进一步调查并尝试找出发生这种情况的原因

更新

使用

DispatchQueue.main.sync

而不是

DispatchQueue.main.async

解决了这个问题。

【讨论】:

你好。我不明白你把那条线放在另一条旁边是什么意思。你的意思是你把这条线放在队列调用之前?【参考方案3】:
DispatchQueue.main.asyncself.collectionView?.reloadData()
    collectionView?.backgroundColor = UIColor.white
    collectionView?.register(ItemCell.self, forCellWithReuseIdentifier: cellId)

在您注册手机之前,您正在重新加载数据。

首先注册您的单元格和数据源并委托方法,最后重新加载数据。

编辑:

我看到你编辑了你的帖子。

但是,在您注册手机之前,您就是fetchData()。因此,在您注册了所有单元格、数据源和委托之后,再次移动 fetchData 方法。

【讨论】:

这是有道理的。但是,即使我将其更改为collectionView?.backgroundColor = UIColor.white collectionView?.register(ItemCell.self, forCellWithReuseIdentifier: cellId) collectionView?.contentInset = UIEdgeInsetsMake(50, 0, self.view.frame.height, self.view.frame.width) collectionView?.scrollIndicatorInsets = UIEdgeInsetsMake(50, 0, 0, self.view.frame.width) fetchData() DispatchQueue.main.asyncself.collectionView?.reloadData(),它也不起作用 @J.GS.Han 你没有设置 collectionView.delegate = self 和 collectionView.datasource = self ,我的回答应该更清楚,但这是你现在唯一的问题。另外我认为您需要将 UICollectionViewDataSourceUICollectionViewDelegate 添加到您的类中的代码中。 感谢您的回复!我已尝试根据您建议的解决方案更新我的代码,但效果不佳。我还尝试将 UICollectionViewDataSourceUICollectionViewDelegate 添加到我的班级,但它抱怨说“'ItemcollectionViewController' 与协议 'UICollectionViewDataSource'' 的冗余一致性” @J.GS.Han 我看到你正在使用 UICollectionViewController,然后设置 self 就是你所需要的,你应该很高兴。只要确保在 numberOfItemsInSection 方法中更改项目数时调用 reloadData 即可。但是,我无法测试您的代码,因为我没有使用 Swift 编写代码,但通常除了我为您指出的这些错误之外,我看不到任何错误。 我尝试添加 UICollectionViewDataSourceUICollectionViewDelegate 作为我班级的超类

以上是关于UICollectionView reloadData() 不会更新集合视图中的单元格的主要内容,如果未能解决你的问题,请参考以下文章

带有 TableView 和 CollectionView 的 UiView 不会随机刷新

折叠UICollectionView

-[UICollectionView _endItemAnimations] 中的 UICollectionView 断言失败

如何滚动另一个 UICollectionView 下方的 UICollectionView?

UICollectionView 单元内部已加载,但 UICollectionView 未显示

UICollectionView 断言失败 -[UICollectionView _updateWithItems:tentativelyForReordering:]