BlackHatSamurai BlackHatSamurai - 1 month ago 7
iOS Question

TableView is Nil

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?

Answer

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.)