0

I am getting this exception:

Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[ setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key ProductsCollection.'

I read previous posts about this, and I checked twice - and my UIVewCollection (ProductsCollection) is linked to the outlet.

My Class :

class SellProductsView: ProductsCollectionViewController
{

override func viewDidLoad()
{

    // Do any additional setup after loading the view.
    self.ProductsCollection.delegate = self
    self.ProductsCollection.dataSource = self;

    LoadProducts(productsToSellOrBuy: "ToSell")

    super.viewDidLoad()

}

override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
    if segue.identifier == "view_product_information"
    {
        let prodPageView = segue.destination as! SellProductPageView
        PrepareProductForSegue(prodPageView: prodPageView)

    }
}

}

My base class :

class ProductsCollectionViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource
{

@IBOutlet weak var ProductsCollection: UICollectionView!

var ref: DatabaseReference?
var databaseHandle: DatabaseHandle?


@IBAction func unwindFromProductPageView(segue: UIStoryboardSegue)
{

}

var products = [Product]()

override func viewDidLoad()
{

    // Do any additional setup after loading the view.
    self.ProductsCollection.delegate = self
    self.ProductsCollection.dataSource = self;

    super.viewDidLoad()

}

internal func LoadProducts(productsToSellOrBuy: String)
{

    if productsToSellOrBuy != "ToBuy" && productsToSellOrBuy != "ToSell"
    {
        // Throw error
    }
    // Set firebase reference
    ref = Database.database().reference()
    let loggedOnUserID = Auth.auth().currentUser?.uid
    // Retrieve the products and listen for changes
    databaseHandle = ref?.child("Products").observe(.childAdded, with:
        { (snapshot) in

            // Code to execute when new product is added
            let prodValue = snapshot.value as? NSDictionary
            let prodToLoad = prodValue?[productsToSellOrBuy] as? Bool // Checks if this is to sell or buy

            if loggedOnUserID != prodValue?["Owner"] as? String, prodToLoad == true
            {
                let prodName = prodValue?["Name"] as? String ?? ""
                let prodPrice = prodValue?["Price"] as? Double ?? -1
                let prodDesc = prodValue?["Description"] as? String ?? ""
                let prodURLS = prodValue?["MainImage"] as? String
                let prodAmount = prodValue?["Amount"] as? Int ?? 0

                let prodID = snapshot.key

                let prodToAddToView = Product(name: prodName, price: prodPrice, currency: "NIS", description: prodDesc, location: "IL",
                                              toSell: false, toBuy: false, owner: "No one", uniqueID: prodID, amount: prodAmount, mainImageURL: prodURLS)

                self.products.append(prodToAddToView)
                DispatchQueue.main.async {
                    self.ProductsCollection.reloadData()
                }
            }
    })
}

override func didReceiveMemoryWarning()
{
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

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

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "product_collection_cell", for: indexPath) as! ProductsCollectionViewCell
    //cell.ProductName.text

    let requestListenRef = ref?.child("Products").child(products[indexPath.row].UniqueID()).child("MainImage")
    requestListenRef?.observe(DataEventType.value, with:
        {
            (snapshot) in

            let mainImage = snapshot.value as? String

            if mainImage == nil
            {
                // No main image exists
                cell.ProductImageView.image = UIImage(named: "DefaultProductImage")
            }
            else
            {
                // Main Image exists
                let url = URL(string: mainImage!)
                if let data = try? Data(contentsOf: url!)
                {
                    cell.ProductImageView.image = UIImage(data: data)
                }
            }
    })

    // Set fields
    let prodInCell = products[indexPath.row]
    cell.ProductName.text = prodInCell.Name()
    cell.ProductPrice.text = String(prodInCell.Price())
    cell.productUniqueID = prodInCell.UniqueID()
    return cell
}

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath)
{
    // Display selected Item
    prodToLoad = products[indexPath.row]


    performSegue(withIdentifier: "view_product_information", sender:self  )
}

var prodToLoad: Product?

override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
    if segue.identifier == "view_product_information"
    {
        let prodPageView = segue.destination as! ProductPageView
        PrepareProductForSegue(prodPageView: prodPageView)

    }
}

internal func PrepareProductForSegue(prodPageView: ProductPageView)
{
    prodPageView.productToDisplay = prodToLoad

    prodPageView.pictures = [UIImageView] ()

    if (prodToLoad?.Images().count != 0)
    {
        let mainImage = prodToLoad?.GetMainImageURLString()

        // Main Image exists
        let url = URL(string: mainImage!)
        if let data = try? Data(contentsOf: url!)
        {
            let imageView = UIImageView()
            imageView.image = UIImage(data: data)
            prodPageView.pictures?.append(imageView)
        }
    }
    else
    {
        let imageView = UIImageView()
        imageView.image = #imageLiteral(resourceName: "DefaultProductImage")
        prodPageView.pictures?.append(imageView)
    }
}
/*
 // MARK: - Navigation

 // In a storyboard-based application, you will often want to do a little preparation before navigation
 override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
 // Get the new view controller using segue.destinationViewController.
 // Pass the selected object to the new view controller.
 }
 */
}

My UICollectionView connection

Also :

When I delete the connection, app doesn't crash. Once I reconnect, it crashes again. The ProductsCollection is now shared between two INHERITING views.

Ofri
  • 289
  • 5
  • 17
  • Have you tried rewiring the outlet, like actually remove and add it back? Sometimes it fixes this kind of problem for me. In my case I copied/pasted a part of XIB content from another XIB, turns out there's something wrong in XCode even if everything seems to be correct. – aunnnn Feb 24 '18 at 16:37
  • Thing is, this UICollectionViewOutlet is shared between two different views (Both inherit it), and one of them works fine.. – Ofri Feb 24 '18 at 16:44
  • I deleted the connection, and it didn't crash. I re-connected it and it crashed again. – Ofri Feb 24 '18 at 16:53

0 Answers0