Not Loading NSPopupbutton. Why?

Hello: I am trying to load an NSPopupButton from a property list, but running the code below results in a fatal error: "Unexpectedly found nil while implicitly unwrapping an Optional value" on line i4. The debug output shows the following:

figures count 4

viewDidLoad() figures count 4

Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value: file /Users/wlionelwilliams/Desktop/ScorcentMasterReview/ScorcentMasterReview/FiguresViewController.swift, line 109


Line 10 seems to suggest that the items for the Popupbutton list is available. What am I missing?


overridefunc viewDidLoad() {
        super.viewDidLoad()
        if let filePath = Bundle.main.path(forResource: "TFigures", ofType: "plist") {
                    print("filePath", filePath)
                    figures = Figure.figuresList(filePath)
                        print("figures count", figures.count)
                   }
                  
      //             figuresButton.removeAllItems()
                   print(#function, "figures count", figures.count)
                  
                  
        for figure in figures {
            figuresButton.addItem(withTitle:figure.title)
                        }
        print ("itemsCount", title!.count)
                selectedFigure = figures [0]
                figuresButton.selectItem(at: 0)
       
    }

Accepted Reply

Thanks.


So, crash is on

figuresButton.addItem(withTitle:figure.title) // Thread 1: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value


Could come from:

  • figuresButton. (most likely)
  • figure.title

Need to check if nil or not:


        for figure in figures {
            print("figure", figure, "figureButton", figuresButton)
            print("item to add", figure.title)
            figuresButton.addItem(withTitle:figure.title)  // Thread 1: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
            print("added item", figure.title)
        }


My guess is that lines 2 and 3 will print once, with figureButton nil.


If so, we'll have to find why.

Replies

How did you declare figuresButton ?

Do you create it in IB ? If so, have you checked the connection to the IBOutlet ?


Are you sure the crash occurs line 14 and not 16 ?

What is title ?


Should change like this for testing:


        for figure in figures {
            print("figure.title", figure.title)
            figuresButton.addItem(withTitle: figure.title)
         }
          if title == nil {
               print("Title is nil")     
          } else {
              print ("itemsCount", title!.count) 
              selectedFigure = figures [0]
              figuresButton.selectItem(at: 0)
      }
    }

Hello Claude31:

I checked the connection. It shows connected in the Connections Inspector.

The line I indicated is throwing the fatal error: line 80 for complete code.


Here is the full code:


import Cocoa
class FiguresViewController: NSViewController {
    var figures = [Figure]()
    var selectedFigure: Figure?
    var figureId:String = ""
    @IBOutlet weak var figureImage: NSImageView!
     var selectedProduct: Product? {
            didSet {
              updateUI()
            }
    }
     override func viewWillAppear() {
          super.viewWillAppear()  
          updateUI()
        }
   
     func updateUI() {
      //1
      if isViewLoaded {
          if let figure = selectedFigure {
            figureImage.image = figure.image
             
          } 
        }
    }
    @IBAction func valueChanged(_ sender: NSPopUpButton) {
       
        if let _ = sender.selectedItem?.title,
        let index = figures.firstIndex(where: {$0.title == title}) {
            selectedFigure = figures[index]
        }
              }
    @IBOutlet weak var figuresButton: NSPopUpButton!
    struct Figure {
         var selectedFigure: Figures?
                  let title: String
                  var image: NSImage? {
                    get {
                      let i = NSImage(named: figureName)
                      return i
                    }
                  }
             fileprivate let figureName: String
                  static func figuresList(_ filePath: String) -> [Figure] {
                    var figures = [Figure]()
                    if let figuresList = NSArray(contentsOfFile: filePath) as? [[String: Any]] {
                         print("figuresList ##START##", figuresList, "figuresList ##END##")
                      for dict in figuresList {
                      if let figure = Figure(dictionary: dict) {
                         figures.append(figure)
                        }
                      }
                    }
                    print("Figures is", figures)
                    return figures
                  }
                  init?(dictionary: [String: Any]) {
                 guard let title = dictionary["figureId"] as? String,
                       let figureName = dictionary["figureName"] as? String else {
                         print("Initialization of Product failed with \(dictionary)")
                        return nil
                    }
                   self.title = title
                   self.figureName = figureName
    }
}
    override func viewDidLoad() {
        super.viewDidLoad()
        if let filePath = Bundle.main.path(forResource: "TFigures", ofType: "plist") {
                    print("filePath", filePath)
                    figures = Figure.figuresList(filePath)
                        print("figures count", figures.count)
                   }
                  
      //             figuresButton.removeAllItems()
                   print(#function, "figures count", figures.count)
                  
                  
        for figure in figures {
            figuresButton.addItem(withTitle:figure.title)Thread 1: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
                        }
        print ("itemsCount", title!.count)
                selectedFigure = figures [0]
                figuresButton.selectItem(at: 0)
    }
   
    }    class Figures: NSViewController {
         
           override func viewDidLoad() {
   }       super.viewDidLoad()
           
               // Do view setup here.
              

Here is the Console Output:


filePath /Users/wlionelwilliams/Library/Developer/Xcode/DerivedData/ScorcentMasterReview-gnzfghwosuggdydtgxnsezjfynal/Build/Products/Debug/ScorcentMasterReview.app/Contents/Resources/TFigures.plist


figuresList ##START## [["figureName": SCFigures2, "figureId": 3312], ["figureId": 3313, "figureName": SCFigures4], ["figureId": 3314, "figureName": SCFigures6], ["figureId": 3315, "figureName": SCFigures8]] figuresList ##END##


Figures is [ScorcentMasterReview.FiguresViewController.Figure(selectedFigure: nil, title: "3312", figureName: "SCFigures2"), ScorcentMasterReview.FiguresViewController.Figure(selectedFigure: nil, title: "3313", figureName: "SCFigures4"), ScorcentMasterReview.FiguresViewController.Figure(selectedFigure: nil, title: "3314", figureName: "SCFigures6"), ScorcentMasterReview.FiguresViewController.Figure(selectedFigure: nil, title: "3315", figureName: "SCFigures8")]


figures count 4

viewDidLoad() figures count 4


Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value: file /Users/wlionelwilliams/Desktop/ScorcentMasterReview/ScorcentMasterReview/FiguresViewController.swift, line 109

Thanks.


So, crash is on

figuresButton.addItem(withTitle:figure.title) // Thread 1: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value


Could come from:

  • figuresButton. (most likely)
  • figure.title

Need to check if nil or not:


        for figure in figures {
            print("figure", figure, "figureButton", figuresButton)
            print("item to add", figure.title)
            figuresButton.addItem(withTitle:figure.title)  // Thread 1: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
            print("added item", figure.title)
        }


My guess is that lines 2 and 3 will print once, with figureButton nil.


If so, we'll have to find why.

Hello Claude31: here are the results:


figures count 4

viewDidLoad() figures count 4


            print("figure", figure, "figureButton", figuresButton)

figure Figure(selectedFigure: nil, title: "3312", figureName: "SCFigures2") figureButton nil


            print("item to add", figure.title)

item to add 3312


figuresButton.addItem(withTitle:figure.title)

Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value: file /Users/wlionelwilliams/Desktop/ScorcentMasterReview/ScorcentMasterReview/FiguresViewController.swift, line 111

That's what I guessed, gigureButton is nil

figure Figure(selectedFigure: nil, title: "3312", figureName: "SCFigures2") figureButton nil


Remove and remake the connection of figureButton to its IBOutlet

Do an option clean build folder

Hello Claude31:


I did as you suggested but got the same result.

I'll continue checking.


Happy Thanksgiving!!

I read again your code and found a few things.


As for presentation, it is better to have all IBOutlets at the beginning, not scattered in code.

And to group all lifecycle methods at the beginning as well.

But that's just for ease of reading.


More important, that could be cause of error:

You declare var figures several times:

line 3

line 45

So, the one defined line 3 is never initialized.

Is it intentional ?

Same issue probably with selectedFigure


Lines 87 to 90.

class declaration should be on a new line: that cannot compile as is

you have a closing curly brace before super.viewDidLoad ; that cannot compile.


So is it the real code ?


You should first correct those errors and try again

Hello Claude:

In response to your suggestions:

"You declare var figures several times: line 3 and 45"

I am not sure how to correct this because

if I remove from line 3 the following errors arise:

Use of unresolved identifier 'figures' on line 50


Anywhere "figures" is used outside the


struct Figure {


line 45"

I am not sure how to correct this because if I remove from line 45 the following errors arise:

"Instance member 'figures' of type 'FiguresViewController' cannot be used on instance of nested type 'FiguresViewController.Figure'"

on the lines 50 - 55

                         figures.append(figure) 
                        } 
                      } 
                    } 
                    print("Figures is", figures) 
                    return figures


"class declaration should be on a new line: that cannot compile as is

you have a closing curly brace before super.viewDidLoad ; that cannot compile."


That was a copying error.


The current structure of the code is given below:


import Cocoa

class FiguresViewController: NSViewController {
   
    @IBOutlet weak var figuresButton: NSPopUpButton!
   

   var figures = [Figure]()
    var selectedFigure: Figure?
    var figureId:String = ""
   
    @IBOutlet weak var figureImage: NSImageView!
   
    var selectedProduct: Product? {
            didSet {
              updateUI()
              print ("FProcess A")
            }
    }
    override func viewWillAppear() {
         super.viewWillAppear()
          
         updateUI()
       }
     private func updateUI() {
         //1
         if isViewLoaded {
             if let figure = selectedFigure {
               figureImage.image = figure.image
               print ("FProcess B")
               print ("FProcess D")
   
              
             }
            
           }
       }
   
    override func viewDidLoad() {
        super.viewDidLoad()
        if let filePath = Bundle.main.path(forResource: "TFigures", ofType: "plist") {
                    print("filePath", filePath)
                    figures = Figure.figuresList(filePath)
                        print("figures count", figures.count)
                        print ("FProcess G")
                   }
        updateUI()
                  
     //             figuresButton.removeAllItems()
                   print(#function, "figures count", figures.count)
                  
                  
        for figure in figures {
             
            print("figure", figure, "figuresButton", figuresButton as Any)
            print("item to add", figure.title)
            print ("FProcess H")
            figuresButton.selectItem(at: 0)
            figuresButton.addItem(withTitle:figure.title)
           
                           }
              if title == nil {
                     print("Title is nil")
                } else {
                    print ("itemsCount", title!.count)
    }
   
//       selectedFigure = figures [0]
    }    
    @IBAction func valueChanged(_ sender: NSPopUpButton) {

    if let title = sender.selectedItem?.title,
        let index = figures.firstIndex(where: {$0.title == title}) {
            selectedFigure = figures[index]
            print ("FProcess F")
        }
              }

    struct Figure {
   
                  let title: String
                  var image: NSImage? {
                    get {
                      let i = NSImage(named: figureName)
                        print("FProcess J")
                      return i
                    }
                  }
         
             fileprivate let figureName: String
         
                  static func figuresList(_ filePath: String) -> [Figure] {
              var figures = [Figure]()
                    print ("FProcess K")
         
                    if let figuresList = NSArray(contentsOfFile: filePath) as? [[String: Any]] {
                         print("figuresList ##START##", figuresList, "figuresList ##END##")
                      for dict in figuresList {
                      if let figure = Figure(dictionary: dict) {
                         figures.append(figure)
                        print ("FProcess L")
                        }
                      }
                    }
                    print("Figures is", figures)
                    return figures
                   
                  }
         
                  init?(dictionary: [String: Any]) {
                  
                 guard let title = dictionary["figureId"] as? String,
                       let figureName = dictionary["figureName"] as? String else {
                         print("Initialization of Product failed with \(dictionary)")
                        return nil
                    }
                    print("FProcess M")
                   self.title = title
                   self.figureName = figureName

    }
}
    class Figures: NSViewController {
        
           override func viewDidLoad() {
               super.viewDidLoad()
            print ("Process C")
          
               // Do view setup here.
              
            }
           
       }
   
}


Thanks for your assistance.

My mistake, figures (of line 3) is set on line 43.

Just shows that reusing the same name, even it is valid, makes it harder to follow code.


Where is the crash now ? Should be line 58, not 59.

Hello Claude:


I really appreciate all the help you provided.


The problem was that I had a connection to another ViewController (Storyboard Scene) that I discarded earlier with the Same name as the one I was using. I didn't delete it because it had some images I wanted to use later but should have removed the connection. So the FiguresButton (NSPopupbutton) was not being recognized.


Soon as I disconnected the old one, everything worked.


Thanks for your assistance. I am going to mark the answer as correct.

Really good you solved it.