17

How do I know that the UICollectionView has been loaded completely? I'm trying to reproduce this solution in Swift, but I'm having trouble reading the Obj-C. Can someone help?

Community
  • 1
  • 1
Grant Park
  • 1,004
  • 1
  • 9
  • 29

7 Answers7

12

SWIFT 3: version of @libec's answer

override func viewDidLoad() {
    super.viewDidLoad()
    collectionView.addObserver(self, forKeyPath: "contentSize", options: NSKeyValueObservingOptions.old, context: nil)
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    collectionView.removeObserver(self, forKeyPath: "contentSize")
}

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    if let observedObject = object as? UICollectionView, observedObject == collectionView {
        print("done loading collectionView")
    }
}
Elijah
  • 8,381
  • 2
  • 55
  • 49
Salil Junior
  • 424
  • 4
  • 12
11

If you wanna go with the approach from the question you linked, then:

override func viewDidLoad() {
    super.viewDidLoad()
    self.collectionView?.addObserver(self, forKeyPath: "contentSize", options: NSKeyValueObservingOptions.Old, context: nil)
}

override func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, change: [NSObject : AnyObject], context: UnsafeMutablePointer<Void>) {
    if let observedObject = object as? UICollectionView where observedObject == self.collectionView {
        print(change)
    }
}

override func viewWillDisappear(animated: Bool) {
    super.viewWillDisappear(animated)
    self.collectionView?.removeObserver(self, forKeyPath: "contentSize")
}
libec
  • 1,555
  • 1
  • 10
  • 19
4

worked for me without any complexity.

self.collectionView.reloadData()
    self.collectionView.performBatchUpdates(nil, completion: {
        (result) in
        // ready
    })

A completion handler block to execute when all of the operations are finished. This block takes a single Boolean parameter that contains the value true if all of the related animations completed successfully or false if they were interrupted. This parameter may be nil.

YodagamaHeshan
  • 4,996
  • 2
  • 26
  • 36
3

Simpler approach would be to just use performBatchUpdates function of the collectionView like this:

collectionView?.performBatchUpdates(nil, completion: { _ in
     // collectionView has finished reloading here
})
Vinayak
  • 523
  • 1
  • 9
  • 20
2

Its Late to answer,
At viewDidAppear you can get it by:

float height = self.myCollectionView.collectionViewLayout.collectionViewContentSize.height;

Maybe when you reload data then need to calculate a new height with new data then you can get it by: add observer to listen when your CollectionView finished reload data at viewdidload:

[self.myCollectionView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionOld context:NULL];

Then add bellow function to get new height or do anything after collectionview finished reload:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary  *)change context:(void *)context
{
    //Whatever you do here when the reloadData finished
    float newHeight = self.myCollectionView.collectionViewLayout.collectionViewContentSize.height;    
}

And don't forget to remove observer:
Write the code in viewWillDisappear

[self.myCollectionView removeObserver:self forKeyPath:@"contentSize" context:NULL];


For more information please look into the answer https://stackoverflow.com/a/28378625/6325474

Er. Vihar
  • 1,495
  • 1
  • 15
  • 29
0

In my case the problem was that collection view was not fully reloaded, so we have to wait until collection view 'reloadData' finishes:

    self.customRecipesCV.reloadData()

        DispatchQueue.main.async {
            if let _index = self.selectCustomRecipeAtIndex {
                let nextIndexpath = IndexPath(row:index, section:0)
                self.customRecipesCV.scrollToItem(at: nextIndexpath, at: .centeredHorizontally, animated: true)

            }
        }
0

This is my implementation of loading indicator while reloading collection view data with this extension.

extension UICollectionView {
    func reloadData(completion: @escaping ()->()) {
        UIView.animate(withDuration: 0, animations: { self.reloadData() })
        { _ in completion() }
    }
}

... somewhere in code ...

collectionView.isHidden = true
loadingView.startAnimating()
DispatchQueue.main.async {
    self.collectionView.contentOffset.x = 0
    self.collectionView.reloadData {
        self.loadingView.stopAnimating()
        self.collectionView.isHidden = false
    }
}
MarekB
  • 612
  • 6
  • 12