Problem with "unresolved and undeclared identifiers"

Hello:


I have this piece of code that seems very straightforward but three errors persist and I can't figure out why.

lines 6, 7, 21 raise errors but I thought that the variable was declared on lines 6 and 7!



import Cocoa

class ViewController: NSViewController {
privatevar overviewViewController: OverviewController?
privatevar detailViewController: DetailViewController?
privatevar products = [Product]() //Unresolved Identifier 'Product'
var selectedProduct: Product? //Undeclared iidentifier 'Product'
@IBActionfunc valueChanged(_ sender: NSPopUpButton) {
        detailViewController?.selectedProduct = selectedProduct
iflet bookTitle = sender.selectedItem?.title,
let index = products.index(where: {$0.title == bookTitle}) {
            selectedProduct = products[index]
        }
        overviewViewController?.selectedProduct = selectedProduct
    }

@IBOutletweakvar productsButton: NSPopUpButton!
overridefunc viewDidLoad() {
super.viewDidLoad()
iflet filePath = Bundle.main.path(forResource: "Products", ofType: "plist") {
            products = Product.productsList(filePath) //Unresolved Identifier 'Product'
        }
        //1
        productsButton.removeAllItems()
        //2
for product in products {
            productsButton.addItem(withTitle: product.title)
        }
        //3
        selectedProduct = products[0]
        productsButton.selectItem(at: 0)// Do any additional setup after loading the view.
    }
overridevar representedObject: Any? {
didSet {
            // Update the view, if already loaded.
        }
    }
overridefunc prepare(for segue: NSStoryboardSegue, sender: Any?) {
guardlet tabViewController = segue.destinationController
as? NSTabViewController else { return }
for controller in tabViewController.children {
iflet controller = controller as? OverviewController {
                overviewViewController = controller
                overviewViewController?.selectedProduct = selectedProduct
            }
elseiflet controller = controller as? DetailViewController {
                detailViewController = controller
                detailViewController?.selectedProduct = selectedProduct
            }
        }
    }
}

Accepted Reply

You have defined Product struct inside a ViewController (in fact inside viewDidLoad) and try to use in another: it is not visible there.


Just get it out of the class, that will work.


import Cocoa

struct Product {

          let title: String
          let audience: String
          let descriptionText: String
          let price: NSNumber
          var image: NSImage? {
            get {
              let i = NSImage(named: imageName)
              return i
            }
          }

          fileprivate let imageName: String

          static func productsList(_ fileName: String) -> [Product] {
            var products = [Product]()

            if let productList = NSArray(contentsOfFile: fileName) as? [[String: Any]] {
              for dict in productList {
                if let product = Product(dictionary: dict) {
                  products.append(product)
                }
              }
            }
            return products
          }

          init?(dictionary: [String: Any]) {
            guard let title = dictionary["Name"] as? String,
              let audience = dictionary["Audience"] as? String,
              let descriptionText = dictionary["Description"] as? String,
              let price = dictionary["Price"] as? NSNumber,
              let imageName = dictionary["Imagename"] as? String else {
                return nil
            }

            self.title = title
            self.audience = audience
            self.descriptionText = descriptionText
            self.price = price
            self.imageName = imageName
          }
 }


class Products: NSViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do view setup here.
     }
   
}


Take care to naming:

dictionary["Imagename"]

Is it Imagename or mageName for the key ?


You could simplify the writing or image computed property:

        var image: UIImage? {
            return UIImage(named: imageName)
        }

Replies

Your code shown lacks many required whitespaces and generates plenty of errors.

They may have been lost while you post your question, but you should be careful enough to show some code causing compile time errors.


Assuming the following code is recovered correctly:

import Cocoa

class ViewController: NSViewController {
    private var overviewViewController: OverviewController?
    private var detailViewController: DetailViewController?
    private var products = [Product]() //Unresolved Identifier 'Product'
    var selectedProduct: Product? //Undeclared iidentifier 'Product'
    @IBAction func valueChanged(_ sender: NSPopUpButton) {
        detailViewController?.selectedProduct = selectedProduct
        if let bookTitle = sender.selectedItem?.title,
            let index = products.index(where: {$0.title == bookTitle}) {
            selectedProduct = products[index]
        }
        overviewViewController?.selectedProduct = selectedProduct
    }
    
    @IBOutlet weak var productsButton: NSPopUpButton!
    override func viewDidLoad() {
        super.viewDidLoad()
        if let filePath = Bundle.main.path(forResource: "Products", ofType: "plist") {
            products = Product.productsList(filePath) //Unresolved Identifier 'Product'
        }
        //1
        productsButton.removeAllItems()
        //2
        for product in products {
            productsButton.addItem(withTitle: product.title)
        }
        //3
        selectedProduct = products[0]
        productsButton.selectItem(at: 0)
        // Do any additional setup after loading the view.
    }
    override var representedObject: Any? {
        didSet {
            // Update the view, if already loaded.
        }
    }
    override func prepare(for segue: NSStoryboardSegue, sender: Any?) {
        guard let tabViewController = segue.destinationController
            as? NSTabViewController else { return }
        for controller in tabViewController.children {
            if let controller = controller as? OverviewController {
                overviewViewController = controller
                overviewViewController?.selectedProduct = selectedProduct
            }
            else if let controller = controller as? DetailViewController {
                detailViewController = controller
                detailViewController?.selectedProduct = selectedProduct
            }
        }
    }
}


The problem is clear enough, the type `Product` is not visible for the Swift compiler when it compiles this file.


Please clarify how and where you declare the type `Product`.

If you have defined Product as fileprivate in another file, it will not be visible here.


Or maybe you mispelled Product (includeing upper/lowercase)

Hello:

In the file Products.Swift there is this code: Why might the other files not recognize the declaration here?

import Cocoa

class Products: NSViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do view setup here.
       
        struct Product {

          let title: String
          let audience: String
          let descriptionText: String
          let price: NSNumber
          var image: NSImage? {
            get {
              let i = NSImage(named: imageName)

              return i
            }
          }

          fileprivate let imageName: String

          static func productsList(_ fileName: String) -> [Product] {
            var products = [Product]()

            if let productList = NSArray(contentsOfFile: fileName) as? [[String: Any]] {
              for dict in productList {
                if let product = Product(dictionary: dict) {
                  products.append(product)
                }
              }
            }

            return products
          }

          init?(dictionary: [String: Any]) {
            guard let title = dictionary["Name"] as? String,
              let audience = dictionary["Audience"] as? String,
              let descriptionText = dictionary["Description"] as? String,
              let price = dictionary["Price"] as? NSNumber,
              let imageName = dictionary["Imagename"] as? String else {
                return nil
            }

            self.title = title
            self.audience = audience
            self.descriptionText = descriptionText
            self.price = price
            self.imageName = imageName
          }

        }

    }
   
}

You have defined Product struct inside a ViewController (in fact inside viewDidLoad) and try to use in another: it is not visible there.


Just get it out of the class, that will work.


import Cocoa

struct Product {

          let title: String
          let audience: String
          let descriptionText: String
          let price: NSNumber
          var image: NSImage? {
            get {
              let i = NSImage(named: imageName)
              return i
            }
          }

          fileprivate let imageName: String

          static func productsList(_ fileName: String) -> [Product] {
            var products = [Product]()

            if let productList = NSArray(contentsOfFile: fileName) as? [[String: Any]] {
              for dict in productList {
                if let product = Product(dictionary: dict) {
                  products.append(product)
                }
              }
            }
            return products
          }

          init?(dictionary: [String: Any]) {
            guard let title = dictionary["Name"] as? String,
              let audience = dictionary["Audience"] as? String,
              let descriptionText = dictionary["Description"] as? String,
              let price = dictionary["Price"] as? NSNumber,
              let imageName = dictionary["Imagename"] as? String else {
                return nil
            }

            self.title = title
            self.audience = audience
            self.descriptionText = descriptionText
            self.price = price
            self.imageName = imageName
          }
 }


class Products: NSViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do view setup here.
     }
   
}


Take care to naming:

dictionary["Imagename"]

Is it Imagename or mageName for the key ?


You could simplify the writing or image computed property:

        var image: UIImage? {
            return UIImage(named: imageName)
        }

Thanks Claude 31 for the correct solution. You guys are really great!