Reputation: 223
I have a collectionView that I am populating using an array I created in a class. The collectionView works but the problem is when I want to segue to another viewController using a button in the collectionViewCell as well as parsing specific data from that cell to the viewController.
An example of what I am trying to do is if I press the button in the cell for the question image I want to segue to the next viewController and I want that viewController's image to be the question image, and maybe i the future add some other data corresponding to it.
I have looked at the other answers on this site and other sites, which got me this far, but there is nothing that I can find to fix this problem for a collectionView. I know that it is similar to a tableView, but when I try and change it based on a tableView, but it doesn't seem to work for me.
This is the image of what the first and second views look like
This is the class i created:
import Foundation
import UIKit
class Information {
var image = ""
var button = ""
var infoOne = ""
var infoTwo = ""
var price = ""
init(image: String, button: String, infoOne: String, infoTwo: String, price: String) {
self.image = image
self.button = button
self.infoOne = infoOne
self.infoTwo = infoTwo
self.price = price
}
//MARK: Carousel Data
static func createData() -> [Information] {
return [
Information(image: "question", button: "Buy One", infoOne: "First Data", infoTwo: "Second Data", price: "10"),
Information(image: "exclamation", button: "Buy Two", infoOne: "First Data", infoTwo: "Second Data", price: "20"),
Information(image: "period", button: "Buy Three", infoOne: "First Data", infoTwo: "Second Data", price: "30"),
Information(image: "all", button: "Buy Four", infoOne: "First Data", infoTwo: "Second Data", price: "40")
]
}
}
This array works just fine when it populates the collectionViewCell.
This is the collectionViewCell
import UIKit
class InfoCollectionViewCell: UICollectionViewCell {
var infomation: Information! {
didSet {
updateUI()
}
}
var addBtnAction : (()-> ())?
@IBOutlet weak var infoImage: UIImageView!
@IBOutlet weak var infoLblOne: UILabel!
@IBOutlet weak var infoLblTwo: UILabel!
@IBOutlet weak var priceLbl: UILabel!
@IBOutlet weak var buyBtn: UIButton!
fileprivate func updateUI() {
infoImage.image! = UIImage(named: infomation.image)!
infoLblOne.text = infomation.infoOne
infoLblTwo.text = infomation.infoTwo
priceLbl.text = infomation.price
buyBtn.setTitle(infomation.button, for: .normal)
}
@IBAction func buyBtnPressed(_ sender: Any) {
print("INFORMATION: \(infomation.image)")
addBtnAction?()
}
override func layoutSubviews() {
super.layoutSubviews()
self.layer.cornerRadius = 5.0
self.clipsToBounds = true
}
}
this is the viewController:
import UIKit
class ViewController: UIViewController {
let collectionViewCellId: String = "carouselCollectionCell"
@IBOutlet weak var collectionView: UICollectionView!
fileprivate var information = Information.createData()
override func viewDidLoad() {
super.viewDidLoad()
self.collectionView.delegate = self
}
}
extension ViewController: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return information.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "infoCell", for: indexPath) as! InfoCollectionViewCell
cell.addBtnAction = {
self.performSegue(withIdentifier: "mainSegue", sender: self)
}
cell.infomation = self.information[indexPath.item]
return cell
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "mainSegue" {
let nxtVC = segue.destination as? DetailViewController
let cell = sender as! InfoCollectionViewCell
let myIndexPath = self.collectionView.indexPath(for: cell)
nxtVC?.infomation = information[(myIndexPath?.item)!]
}
}
}
So when I run the app everything is fine until I press the button to segue and parse data. The app crashes and this is what it is saying is the cause:
This is what is in the output console:
Could not cast value of type 'carousel.ViewController' (0x107992178) to 'carousel.InfoCollectionViewCell' (0x107991f98). 2018-09-28 21:22:52.116698-0400 carousel[1573:38999] Could not cast value of type 'carousel.ViewController' (0x107992178) to 'carousel.InfoCollectionViewCell' (0x107991f98). (lldb)
I would prefer to keep the button if at all possible, but if it is not possible I will change that. I am not sure what it is that I am doing wrong. If there is anything else that I can help with please let me know. Thank you very much.
EDIT:
It seems that I forgot to include one of the important views, the one for the other viewController that is segued to.
Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value
this is the view that i segue to:
import UIKit
class DetailViewController: UIViewController {
@IBOutlet weak var infoImage: UIImageView!
@IBOutlet weak var dataTxtView: UITextView!
var testingImage: UIImage = UIImage()
var infomation: Information! {
didSet {
updateUI()
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
fileprivate func updateUI() {
let images = UIImage(named: infomation.image)
infoImage.image = images
print("Image: \(infomation.image)")
}
}
In the updateUI function I tried to make the infoImage the same as infomation.image but it crashes and states:
Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value
This doesn't make much sense to me because I tried to print what the string of infomation.image is, and it worked, but the moment I try and put it as an image it seems to crash. Thank you again
EDIT2:
I figured out what I was doing wrong. It seems that I was always trying to use an optional string. How i fixed it is that I changed the class I made and instead of a string and turn that into an image it is already an image. I also tried to create an if let statement to remove the optional.
This is what the prepareForSegue looks like in the main ViewController
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "mainSegue" {
let nxtVC = segue.destination as? DetailViewController
let cell = sender as? InfoCollectionViewCell
let myIndexPath = self.collectionView.indexPath(for: cell!)
if let indexPath = myIndexPath {
nxtVC?.infomation = information[indexPath.row]
}
}
}
this is what the viewDidLoad looks like:
override func viewDidLoad() {
super.viewDidLoad()
print("***********TESTINGIMAGE: \(infomation.image!)***********")
infoImage.image = infomation.image!
}
I know that I am unwrapping the image with an ! but i don't know how to remove the optional otherwise. Thank you for the Help.
Upvotes: 1
Views: 279
Reputation: 318804
The problem is that you are assuming that the sender
in prepare
is an instance of the cell but your call to performSegue
is passing self
as the sender. But self
in that case is the view controller, not the cell.
The solution is to pass the cell instead of self
.
cell.addBtnAction = {
self.performSegue(withIdentifier: "mainSegue", sender: cell)
}
Upvotes: 2