1

I have the following class:

import UIKit
import CloudKit

class FirstViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {

    @IBOutlet weak var listTableView: UITableView!
    var list: TLListModel!
    var specificList: CKRecord!




    override func viewDidLoad()
    {
        super.viewDidLoad()
        let myContainer = CKContainer.default()
        list = TLListModel(container: myContainer, viewController: self)
        if(listTableView != nil){
            listTableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
        }

    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        print("number of items: %i", list.lists.count)
        return list.lists.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell:UITableViewCell = listTableView.dequeueReusableCell(withIdentifier: "cell")! as UITableViewCell
        let list: CKRecord = self.list.lists[(indexPath as NSIndexPath).row]
        cell.textLabel?.text = list.value(forKey: "ListName") as? String
        cell.textLabel?.font = UIFont (name: "Slim Joe", size: 20)
        cell.accessoryType = .disclosureIndicator
        return cell
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        print("This object has been selected")
        print(self.list.lists[(indexPath as NSIndexPath).row])

        specificList = self.list.lists[(indexPath as NSIndexPath).row]
        performSegue(withIdentifier: "TLSpecificListSegue", sender: nil)
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "TLSpecificListSegue"{
            if let destinationVC = segue.destination as? TLSpecificListViewController{
                destinationVC.listObject = specificList
            }
        }
    }

    func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool
    {
        return true
    }

    func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath)
    {
        if editingStyle == .delete
        {
            let cloudkit = TLCloudKitHelper()            
            cloudkit.deleteListItem(self.list.lists[(indexPath as NSIndexPath).row], callback: { (listName) in
                TLAlertHelper.notifyUser("List Deleted", message: NSString(format: "List for %@ successfully deleted", listName) as String, sender: self)

                 let myContainer = CKContainer.default()
                 self.list = TLListModel(container: myContainer, viewController: self)
                DispatchQueue.main.async {
                    self.listTableView.reloadData()
                }

            })


        }
    }

}

When I call it from another view controller using the following method:

@IBAction func createListAction(_ sender: AnyObject) {
    let cloudkit = TLCloudKitHelper()
    let listArray = createListFromTextField(textInputArea.text)

    if(!(listNameTextField.text?.isEmpty)!){
        cloudkit.createList(listNameTextField.text!) { (response) in
            let listId = response
            if (!listArray.isEmpty){
                for item in listArray{
                    cloudkit.saveItemRecord(item, listId: listId, recordName: response)
                }
            }
            let fvc: FirstViewController = FirstViewController()
            DispatchQueue.main.async {
                self.present(fvc, animated: true, completion: nil)
            }

        }
    }else{
        TLAlertHelper.notifyUser("Give the list a name", message: "You need to give you list a name...", sender:self)
    }


}

I get an error saying fatal error: unexpectedly found nil while unwrapping an Optional value

I don't understand why I am getting this error. I've tried looking at the answers here: Simple UITableView in Swift - unexpectedly found nil but I none of those answers helped. Can someone tell me why this this crashing and how I can fix it?

Community
  • 1
  • 1
BlackHatSamurai
  • 23,275
  • 22
  • 95
  • 156

1 Answers1

6

The problem is this line:

let fvc: FirstViewController = FirstViewController()

This creates a blank FirstViewController instance — one completely unconnected with the interface you designed in the storyboard. Its view is empty. It has no table view in it. Therefore, since there is no table view, there is no outlet connection from any table view, and listTableView remains nil.

What you want to do is get the FirstViewController instance from the storyboard, the one whose interface you have already designed in the storyboard. You can do that by talking to the storyboard and using the FirstViewController's identifier, i.e., call instantiateViewController(withIdentifier:). (You might have to give the FirstViewController in the storyboard an identifier for this purpose.)

EDIT This is such a common mistake that I've written a blog post about it: http://www.programmingios.net/dont-make-a-new-instance-by-mistake/

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • Thanks @matt I never would have got that. This new swift 3 really has me turned around and I feel like things are more complicated now. You use to be able create a view controller and present it. Apparently that isn't the case now. :/ – BlackHatSamurai Oct 17 '16 at 02:08
  • 1
    This has nothing to do with Swift 3. Your code would not have worked in Swift 2 either. – matt Oct 17 '16 at 02:08
  • Hmmm... Well maybe it's a storyboard thing. I'm use to using xibs. I've never had this issue before. – BlackHatSamurai Oct 17 '16 at 02:10
  • Right, a storyboard thing is exactly what it is, and my answer was wrong. Fixed now, though! Thanks for sticking with me here. – matt Oct 17 '16 at 02:10
  • Okay, I think I'm done massacring that answer. :( Let me know if you have questions. – matt Oct 17 '16 at 02:13
  • I think it's right. I just have to figure out how to do everything you suggested. I'll let you know once I have it though. Thanks for all the help :) – BlackHatSamurai Oct 17 '16 at 02:17
  • Finally got it! Thanks for all your help! I really appreciated it. It just goes to show why I hate working with storyboards ;) – BlackHatSamurai Oct 17 '16 at 02:26
  • They are not so bad as long as you understand what they are. What didn't click for you is that each scene in a storyboard is a _view controller instance_. It was _that particular instance_ that you needed to talk to. Trust me, your knowledge of xib files and how to do things without segues will _help_ you understand storyboards. You will know what's _really_ going on. – matt Oct 17 '16 at 02:31
  • You're absolutely right about what I didn't understand. I never realized that each was it's own instance. Thanks again for all the help. I appreciate it. – BlackHatSamurai Oct 17 '16 at 02:41