Reputation: 1002
I'm working on an iPad app that should display 4 CollectionViews next to each other. The height of the collection views should be 3/4 of the screen, so the layout will look something like this:
___________________
| top content |
|-------------------|
| CV | CV | CV | CV |
|____|____|____|____|
I tried to narrow everything down and created a new project with just one of these collection views, but I keep running into the same problem: when I tap on one of the cells, all of them disappear. To reproduce:
CollectionViewCell.swift: (create the outlet by ctrl-dragging the label to the source code)
import UIKit
class CollectionViewCell: UICollectionViewCell {
@IBOutlet weak var label: UILabel!
}
CollectionViewController.swift: (pay attention to the comment in viewDidLoad implementation)
import UIKit
private let reuseIdentifier = "MyCollectionViewCell"
class CollectionViewController: UICollectionViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Register cell classes
// this has to be removed to work with a custom cell class
// self.collectionView!.register(UICollectionViewCell.self, forCellWithReuseIdentifier: reuseIdentifier)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: UICollectionViewDataSource
override func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 5
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! CollectionViewCell
cell.label.text = "\(indexPath.section)-\(indexPath.row)"
return cell
}
}
change the implementation for ViewController.swift:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let frame = view.frame
let vc = UIStoryboard(name: "Main", bundle: Bundle.main).instantiateViewController(withIdentifier: "CollectionViewController")
vc.view.frame = CGRect(x: 0.0, y: frame.size.height * 0.25, width: frame.size.width, height: frame.size.height * 0.75)
self.view.addSubview(vc.view)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Here's a capture of the iOS simulator:
I hope I didn't forget anything to reproduce the problem. Just in case, I uploaded the project to my dropbox.
https://dl.dropboxusercontent.com/u/607872/CollectionViewBugZip.zip
Can someone tell me what I'm doing wrong?
Upvotes: 5
Views: 3171
Reputation: 12615
Swift 5 / iOS 16
Adding the following two lines, right below where I programmatically instantiate the UIViewController that hosts the UICollectionView worked for me).
I don't know why it works, but I was completely out of ideas and found this on reddit, and it solved it after a couple of hours of me sweating and trying everything I could think of:
self.addChild(vcThatHostsCollectionView)
vcThatHostsCollectionView(toParent: self)
This is the code in my 'consumer' viewcontroller that instantiates the collection view hosting viewcontroller, that includes the two lines shown above.
func configurePagerTabs() {
let rect = CGRectMake(0, 0, UIScreen.main.bounds.width, 35.0)
let pagerTabsViewController = PagerTabsViewController(frame: rect, tabTitles: tabTitles)
self.addChild(pagerTabsViewController)
pagerTabsViewController.didMove(toParent: self)
pagerTabsViewController.delegate = self
pagerTabsView = pagerTabsViewController.view
view.addSubview(pagerTabsView)
}
This is part of the viewcontroller that creates the collection view, to show how it initializes things.
class PagerTabsViewController: UIViewController {
enum Section { case main }
var dataSource : UICollectionViewDiffableDataSource<Section, String>! = nil
var collectionView : UICollectionView! = nil
var tabTitles : [String]! = nil
var delegate : PagerTabsDelegate? = nil
var reuseId = "TabCellReuse"
var frame = CGRect.zero
required init(coder: NSCoder) { fatalError("Not implemented to use with storyboard") }
@objc init(frame: CGRect, tabTitles: [String]) {
super.init(nibName: nil, bundle: nil)
self.tabTitles = tabTitles
self.frame = frame
}
override func loadView() {
collectionView = UICollectionView(frame: frame, collectionViewLayout: createLayout())
collectionView.isPagingEnabled = true
collectionView.delegate = self
collectionView.dataSource = self
collectionView.backgroundColor = .blue
registerCells()
view = collectionView
}
.
.
.
}
Upvotes: 0
Reputation: 13698
Check that your ViewController not deiniting. Write deinit { print("Deinited") }
and place a breakpoint there. In my case CollectionView disappeared because it was been deiniting with viewController that holt it.
Upvotes: 0
Reputation: 1002
Turns out the mistake was in adding the collection view as a subview, which isn't considered good practice. Appearently, when only the subview is added, it's "disconnected" from its view controller.
This did the trick: ViewController.swift
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let frame = view.frame
let vc = UIStoryboard(name: "Main", bundle: Bundle.main).instantiateViewController(withIdentifier: "CollectionViewController")
self.addChildViewController(vc) // <----------- !!!!
vc.didMove(toParentViewController: self) // <-- !!!!
vc.view.frame = CGRect(x: 0.0, y: frame.size.height * 0.25, width: frame.size.width, height: frame.size.height * 0.75)
self.view.addSubview(vc.view)
}
Upvotes: 19