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?
-
Here's the reliable solution: https://stackoverflow.com/a/39798079 – Sébastien Jun 09 '21 at 09:10
7 Answers
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")
}
}

- 8,381
- 2
- 55
- 49

- 424
- 4
- 12
-
-
Doesn't work. observeValue is called each time i scroll the collectionView even contentSize is the same. – TomSawyer Jun 08 '19 at 10:15
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")
}

- 1,555
- 1
- 10
- 19
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.

- 4,996
- 2
- 26
- 36
Simpler approach would be to just use performBatchUpdates function of the collectionView like this:
collectionView?.performBatchUpdates(nil, completion: { _ in
// collectionView has finished reloading here
})

- 523
- 1
- 9
- 20
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

- 1,495
- 1
- 15
- 29
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)
}
}

- 9,493
- 4
- 53
- 47
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
}
}

- 612
- 6
- 12