NSPopup Button is not showing all items in Product List

Hello:


I am using an NSPopup Button from which a user can select items. The items for the button are in a .plist file.

The code is reading the full array of items but only a small number are made available to the User. There are 41 items but only about 13 are shown. Can someone show me how to correct this?


Here is the code:


import Cocoa
 
struct Product{
 
          let title: String
          let points: NSNumber
          var image: NSImage? {
            get {
              let i = NSImage(named: imageName)
              return i
            }
          }
 
        fileprivate let imageName: String
 
          static func productsList(_ filePath: String) -> [Product] {
            var products = [Product]()
 
            if let productList = NSArray(contentsOfFile: filePath) as? [[String: Any]] {
                 print("productList ##START##", productList, "productList ##END##")
              for dict in productList {
                if let product = Product(dictionary: dict) {
                  products.append(product)
                }
              }
            }
            print("Products is", products)
            return products
           
          }
 
          init?(dictionary: [String: Any]) {
            guard let title = dictionary["Prize"] as? String,
              let points = dictionary["Points"] as? NSNumber,
              let imageName = dictionary["imageName"] as? String else {
                 print("Initialization of Product failed with \(dictionary)")
                return nil
            }
            self.title = title
            self.imageName = imageName
            self.points = points

           
          }
}
 
 
class Products: NSViewController {
 
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do view setup here.
     }
    
}


AND this:


import Cocoa

class GroupWorkViewController: NSViewController {
     
        private var overviewController: OverviewController?
        private var detailViewController: DetailViewController?
       
        private var products = [Product]()
        var selectedProduct: Product?
       
       
        @IBAction func valueChanged(_ sender: NSPopUpButton) {
           
           
            if let title = sender.selectedItem?.title,
                let index = products.firstIndex(where: {$0.title == title}) {
                selectedProduct = products[index]
                overviewController?.selectedProduct = selectedProduct
                detailViewController?.selectedProduct = selectedProduct
            }
           
        }
       
       
       
    @IBOutlet weak var productsButton: NSPopUpButton!
   
       
        override func viewDidLoad() {
            super.viewDidLoad()
          
           if let filePath = Bundle.main.path(forResource: "Products", ofType: "plist") {
             print("filePath", filePath)
             products = Product.productsList(filePath)
                 print("products count", products.count)
            }
          
           
      //      if let fileURL = Bundle.main.url(forResource: "Products", withExtension: "plist") {
      //          products = Product.productsList(fileURL)

     //   }
            //1
            productsButton.removeAllItems()
            //2
            for product in products {
                productsButton.addItem(withTitle: product.title)
                selectedProduct = products [0]
            }
            //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 {
                    overviewController = controller
                    overviewController?.selectedProduct = selectedProduct
                }
                else if let controller = controller as? DetailViewController {
                    detailViewController = controller
                    detailViewController?.selectedProduct = selectedProduct
                }
            }
           
        }
       
    }

Accepted Reply

So, you get only this list :

SuperJet

House

SpeedBoat

Jet

Teach

Watch

SuperMansion

Cash

Jewelry

Yacht

Car

HouseBoat

Mansion


Exact ?


Reason is that addItem(withTitle:) adds ONLY if it is a new title.

As you have the same title, the new item replaces the old.

And that is logic, otherwise user cannot understand what is what.


You should add another information (may be the image ?) to the title.


Just to check, you could add a number:


            for (i, product) in products.enumerated {
                productsButton.addItem(withTitle: "\(i)  \(product.title))
            }
            if products.count > 0 { selectedProduct = products [0] }



See documentation about addItem:

Instance Method addItem(withTitle:)


Parameters

title

The title of the menu-item entry. If an item with the same title already exists in the menu, the existing item is removed and the new one is added.


Replies

I tested adding 40 items to NSPopupButton without problem.


So, you may have a problem with products.


Complete with some logs:


     print(#function, "1. products count", products count)          // Should get 41, right ?
            for product in products {
                productsButton.addItem(withTitle: product.title)
                print("2. product", product.title)          // Do you get 41 lines in print log ?     
                selectedProduct = products [0]
            }


Question: why do you put

                selectedProduct = products [0]


inside the loop ? You will repeat assignment 41 times uselessly.

Just check before assigning that products.count > 0

Hello Claude31:


The outputs are Correct:

products count 41

viewDidLoad() 1. products count 41

2. product Car

2. product Yacht

2. product Car

2. product Car

2. product Cash

2. product House

2. product Cash

2. product Car

2. product House

2. product House

2. product Car

2. product Jewelry

2. product Jewelry

2. product Cash

2. product Jewelry

2. product Car

2. product SuperJet

2. product House

2. product Mansion

2. product Jewelry

2. product Yacht

2. product Mansion

2. product Jet

2. product Jewelry

2. product Jet

2. product Car

2. product SpeedBoat

2. product Car

2. product Jet

2. product Car

2. product Mansion

2. product Teach

2. product Watch

2. product Jewelry

2. product SuperMansion

2. product Cash

2. product Jewelry

2. product Yacht

2. product Car

2. product HouseBoat

2. product Mansion


However the list to select from is still about 13.

So, you get only this list :

SuperJet

House

SpeedBoat

Jet

Teach

Watch

SuperMansion

Cash

Jewelry

Yacht

Car

HouseBoat

Mansion


Exact ?


Reason is that addItem(withTitle:) adds ONLY if it is a new title.

As you have the same title, the new item replaces the old.

And that is logic, otherwise user cannot understand what is what.


You should add another information (may be the image ?) to the title.


Just to check, you could add a number:


            for (i, product) in products.enumerated {
                productsButton.addItem(withTitle: "\(i)  \(product.title))
            }
            if products.count > 0 { selectedProduct = products [0] }



See documentation about addItem:

Instance Method addItem(withTitle:)


Parameters

title

The title of the menu-item entry. If an item with the same title already exists in the menu, the existing item is removed and the new one is added.


Hello Claude31:


Thanks. Your suggestions implemented did the trick.


Thanks a million.