Andrew Tuzson
Andrew Tuzson

Reputation: 639

Cannot pass data from collection view to detail view in Xcode

I am a Swift beginner attempting to pass the corresponding name and image of the product contained within a cell of a collection view. I have created a singleton and a data file to simulate pulling this info from the internet. I am struggling to assign the values of the collection view cell to the outlets on the detail view controller. Where am I going wrong? I am struggling to understand how to assign these value correctly. Here are my files:

Collection View File

import UIKit

class ProductVC: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {

@IBOutlet weak var collectionView: UICollectionView!

override func viewDidLoad() {
    super.viewDidLoad()
    collectionView.delegate = self
    collectionView.dataSource = self
}

@IBAction func backButtonPressed(_ sender: Any) {
    dismiss(animated: true, completion: nil)
}

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return DataServices.instance.getProducts().count
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ProductCell", for: indexPath) as? ProductCell {
        let product = DataServices.instance.getProducts()[indexPath.row]
        cell.updateView(product: product)
        return cell
    }
    return ProductCell()
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "ProductDetailVC" {
        var productDetailVC = segue.destination as! ProductDetailVC
        let cell = sender as! UICollectionViewCell
        let indexPath = collectionView.indexPath(for: cell)
        let product = DataServices.instance.getProducts()[(indexPath?.row)!]
    }
}


}

Product Detail View Controller

import UIKit

class ProductDetailVC: UIViewController {

@IBOutlet weak var productName: UILabel!
@IBOutlet weak var productImageView: UIImageView!

var product: Product?

override func viewDidLoad() {
    super.viewDidLoad()
}

func updateView() {
    productName.text = product?.name
    productImageView.image = UIImage(named: (product?.imageName)!)
}


}

Product Model

import Foundation

struct Product {

private(set) public var name: String
private(set) public var imageName: String

init(name: String, imageName: String) {
    self.name = name
    self.imageName = imageName
}

}

Data Model

import Foundation

class DataServices {

static var instance = DataServices()
var productIndex = 0 

private(set) public var categories = [
    Category(imageName: "backpackingBG", title: "BACKPACKING"),
    Category(imageName: "campingBG", title: "CAMPING"),
    Category(imageName: "divingBG", title: "DIVING"),
    Category(imageName: "fishingBG", title: "FISHING"),
    Category(imageName: "hikingBG", title: "HIKING"),
    Category(imageName: "rvBG", title: "RV LIFE")
]

func getCategories() -> [Category] {
    return categories
}

private let products = [
    Product(name: "SLEEPING BAG", imageName: "sleepingBag"),
    Product(name: "CAMPING STOVE", imageName: "campingStove"),
    Product(name: "FOOD COOLER", imageName: "foodCooler"),
    Product(name: "PARACORD BRACELET", imageName: "paracordBracelet"),
    Product(name: "PUP TENT", imageName: "pupTent"),
    Product(name: "TACTICAL KNIFE", imageName: "tacticalKnife")
]

func getProducts() -> [Product] {
    return products
}

}

Upvotes: 1

Views: 1174

Answers (3)

Shehata Gamal
Shehata Gamal

Reputation: 100503

You must implement

optional func collectionView(_ collectionView: UICollectionView, 
         didSelectItemAt indexPath: IndexPath)
{
  self. performSegue(withIdentifier: "ProductDetailVC", sender: indexPath.row)

}

//

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
 if segue.identifier == "ProductDetailVC" {
    var productDetailVC = segue.destination as! ProductDetailVC
    let index = sender as! Int
    let product = DataServices.instance.getProducts()[index]
    productDetailVC.product = product
 }
}

Upvotes: 3

Florian Burel
Florian Burel

Reputation: 3456

In your ProductDetailVC, the updateView() method is never called. You should call it in viewdidLoad. ;)

class ProductDetailVC: UIViewController {

@IBOutlet weak var productName: UILabel!
@IBOutlet weak var productImageView: UIImageView!

var product: Product?

override func viewDidLoad() {
    super.viewDidLoad()
    updateView() // <-- This is what you missed!
}

func updateView() {
    productName.text = product?.name
    productImageView.image = UIImage(named: (product?.imageName)!)
}


}

Also if your segue is never triggered, make sure it is set in the storyboard from a cell template to the ProductDetailVC and that make sure your segue identifier in the storyboard is set to ProductDetailVC (case sensitive).

Finally, in your prepareForSegue method, you are not using your last variable (let product = ...) you should pass it to the productDetailVC .

Cheers,

Upvotes: 1

vp2698
vp2698

Reputation: 1805

You have forgot to pass product,for Pass product

 override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "ProductDetailVC" {
        var productDetailVC = segue.destination as! ProductDetailVC
        let cell = sender as! UICollectionViewCell
        let indexPath = collectionView.indexPath(for: cell)
        let product = DataServices.instance.getProducts()[(indexPath?.row)!]
        productDetailVC.product = product
    }
}

And in ProductDetailVC for update UI

override func viewDidLoad() {
    super.viewDidLoad()
    self.updateView()
}

Upvotes: 2

Related Questions