I have made a collection view programmatically but when set collectionView.delegate = self
and collectionView.dataSource = self
I get a nil while unwrapping an optional. I don't know what I did wrong here.
class MainFeedViewController: UIViewController, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource, UICollectionViewDelegate, UIViewControllerTransitioningDelegate, UIGestureRecognizerDelegate, MyCollectionCell {
let transition = CircularAnimation()
var collectionView: UICollectionView!
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(tapEdit(recognizer:)))
func MyCollectionCell() {
let vc = DescriptionViewController()
self.present(vc, animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.navigationBar.isHidden = true
collectionView.delegate = self
collectionView.dataSource = self
view.backgroundColor = .white
UIApplication.shared.isStatusBarHidden = false
UIApplication.shared.statusBarStyle = .default
view.addSubview(Settings)
view.addSubview(topBar)
view.addSubview(separatorView)
view.addSubview(separatorView2)
Settings.translatesAutoresizingMaskIntoConstraints = false
Settings.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 15).isActive = true
Settings.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
Settings.widthAnchor.constraint(equalToConstant: 50).isActive = true
Settings.heightAnchor.constraint(equalToConstant: 50).isActive = true
separatorView.translatesAutoresizingMaskIntoConstraints = false
separatorView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 40).isActive = true
separatorView.heightAnchor.constraint(equalToConstant: 1).isActive = true
view.addConstraint(NSLayoutConstraint(item: separatorView, attribute: .left, relatedBy: .equal, toItem: Settings, attribute: .right, multiplier: 1, constant: 15))
view.addConstraint(NSLayoutConstraint(item: separatorView, attribute: .right, relatedBy: .equal, toItem: topBar, attribute: .right, multiplier: 1, constant: 0))
separatorView2.translatesAutoresizingMaskIntoConstraints = false
separatorView2.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 40).isActive = true
separatorView2.heightAnchor.constraint(equalToConstant: 1).isActive = true
view.addConstraint(NSLayoutConstraint(item: separatorView2, attribute: .right, relatedBy: .equal, toItem: Settings, attribute: .left, multiplier: 1, constant: -15))
view.addConstraint(NSLayoutConstraint(item: separatorView2, attribute: .left, relatedBy: .equal, toItem: topBar, attribute: .left, multiplier: 1, constant: 0))
topBar.translatesAutoresizingMaskIntoConstraints = false
topBar.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
topBar.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
topBar.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
view.addConstraint(NSLayoutConstraint(item: topBar, attribute: .bottom, relatedBy: .equal, toItem: separatorView, attribute: .top, multiplier: 1, constant: 0))
view.insertSubview(topBar, belowSubview: Settings)
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
let height = (view.frame.width - 16 - 16) * 9/16
layout.sectionInset = UIEdgeInsets(top: 80, left: 0, bottom: 0, right: 0)
layout.itemSize = CGSize(width: view.frame.width, height: height + 16 + 80)
collectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
collectionView?.scrollIndicatorInsets = UIEdgeInsetsMake(80, 0, 0, 0)
collectionView.dataSource = self
collectionView.delegate = self
collectionView.register(Cell.self, forCellWithReuseIdentifier: "cellId")
collectionView.backgroundColor = UIColor.clear
collectionView.addGestureRecognizer(tapGesture)
tapGesture.delegate = self
self.view.addSubview(collectionView)
view.insertSubview(collectionView, belowSubview: topBar)
}
let Settings : UIButton = {
let btn = UIButton()
btn.setTitle("Clotho", for: .normal)
btn.setTitleColor(.white, for: .normal)
btn.layer.cornerRadius = 25
btn.backgroundColor = UIColor.rgb(displayP3Red: 255, green: 165, blue: 0)
btn.titleLabel?.font = UIFont(name: "Pacifico-Regular", size: 16)
btn.addTarget(self, action:#selector(settingsTab), for: .touchUpInside)
return btn
}()
let topBar: UIView = {
let bar = UIView()
bar.backgroundColor = .white
return bar
}()
let separatorView: UIView = {
let view = UIView()
view.backgroundColor = UIColor.rgb(displayP3Red: 211, green: 211, blue: 211)
return view
}()
let separatorView2: UIView = {
let view2 = UIView()
view2.backgroundColor = UIColor.rgb(displayP3Red: 211, green: 211, blue: 211)
return view2
}()
@objc func tapEdit(recognizer: UITapGestureRecognizer) {
if recognizer.state == UIGestureRecognizerState.ended {
let tapLocation = recognizer.location(in: self.collectionView)
if let tapIndexPath = self.collectionView.indexPathForItem(at: tapLocation) {
if (self.collectionView.cellForItem(at: tapIndexPath) as? Cell) != nil {
//do what you want to cell here
}
}
}
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 4
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellId", for: indexPath) as! Cell
cell.Delegate = self
return cell
}
func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
transition.transitionMode = .present
transition.startingPoint = Settings.center
transition.circleColor = Settings.backgroundColor!
return transition
}
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
transition.transitionMode = .dismiss
transition.startingPoint = Settings.center
transition.circleColor = Settings.backgroundColor!
return transition
}
@objc func settingsTab(){
let secondVC = SettingsViewController()
secondVC.transitioningDelegate = self
secondVC.modalPresentationStyle = UIModalPresentationStyle.custom
self.present(secondVC, animated: true, completion: nil)
}
}
I set a var Delegate: MyCollectionCell?
in my cell with a protocol
import UIKit
protocol MyCollectionCell {
func MyCollectionCell()
}
class Cell: UICollectionViewCell {
var Delegate: MyCollectionCell?
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
let TapGesture = UITapGestureRecognizer(target: self, action: #selector(Cell.tapEdit(sender:)))
addGestureRecognizer(TapGesture)
TapGesture.delegate = MainFeedViewController()
}
//other setup code...
@objc func tapEdit(sender: UITapGestureRecognizer) {
Delegate?.MyCollectionCell()
}
You haven't actually created the collection view anywhere.
This line:
var collectionView: UICollectionView!
creates a variable ready to hold the collection view (and the ! character indicates you should populate the variable in the viewDidLoad method) but you don't actually create the instance of the UICollectionView and assign it to that variable.
So when you try to set the delegate and data source the collection view variable is still nil and hence you get an error.
You need to actually create the instance of a UICollectionView which is also going to involve creating an instance of a UICollectionViewLayout (or a subclass of it like UICollectionViewFlowLayout).
At the most basic level you should do something like this:
let layout = UICollectionViewFlowLayout()
layout.itemSize = CGSize(width: 100, height: 100)
collectionView = UICollectionView(frame: CGRect(x: 0, y: 0, width: 500, height: 500), collectionViewLayout: layout)
although of course you should adjust the frame and the parameters of the layout to suit your usage requirements.