UICollectionView reloadData() does not update cells in the collection view

天涯浪子 提交于 2019-12-12 03:47:06

问题


Here's high level description of what I'm trying to achieve; 1. fetch data 2. save the fetched data in an array object 3. update collection view with the size of the array

Here's my code

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.addOperation{self.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)
  }
}

In the log I could see the following statements:

in the method 0

size of the array is 3

and could not see any cell from my view.

Can someone advise me what I've done wrong? Thanks in advance.

EDIT 1 Now I'm fetching data after registering the customised cells. However, it still doesn't work

updated code:

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.async{self.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)
  }
}

EDIT 2

The following code is my querying method

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()
}

FYI: I know I'm not using passed user credential, it's just a copy and paste error from my different query method


回答1:


I'm not sure how this resolved this issue. But I just added

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

just next to

OperationQueue.main.addOperation{self.collectionView?.reloadData()}

and it magically works.. even thought when I go back and come back to the screen, it does not show anything.

I'll investigate it more and try to find out why this is happening

Updated

Using

DispatchQueue.main.sync

instead of

DispatchQueue.main.async

resolved the problem.




回答2:


When the DataSource changes, reloadData does not update the cell that has been displayed in the view. Reload visible items will do this job.

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



回答3:


DispatchQueue.main.async{self.collectionView?.reloadData()}
    collectionView?.backgroundColor = UIColor.white
    collectionView?.register(ItemCell.self, forCellWithReuseIdentifier: cellId)

You are reloading data before you even have registered your cell.

Register your cell and datasource and delegate methods FIRST, and reload data LAST.

EDIT:

I see you edited your post.

But again, you are fetchData() before you even have registered your cell. So, again, move the fetchData method AFTER you have registered all cells , datasources and delegates.



来源:https://stackoverflow.com/questions/42241629/uicollectionview-reloaddata-does-not-update-cells-in-the-collection-view

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!