-4

I'm trying to find where is the nil when unwrapping. Here is the piece of code I have. The lines where the fatal errors are found are at:

1st file:

date = dateFormatter().date(from: dictionary[kDATE] as! String)!

2nd file:

self.allLists.append(ShoppingList.init(dictionary: currentList))

This is from the shoppingList.swift file and the function is called in a controller

import Foundation
import Firebase

class ShoppingList{
    let name: String
    var totalPrice: Float
    var totalItems: Int
    var id: String
    var date: Date
    var ownerId: String

    init(_name: String, _totalPrice: Float = 0, _id: String = "") {
        name = _name
        totalPrice = _totalPrice
        totalItems = 0
        id = _id
        date = Date()
        ownerId = "1234"
    }

    //creates shopping list item from this dictionary

    init(dictionary: NSDictionary) {

        name = dictionary[kNAME] as! String
        totalPrice = dictionary[kTOTALPRICE] as! Float
        totalItems = dictionary[kTOTALITEMS] as! Int
        id = dictionary[kSHOPPINGLISTID] as! String
        date = dateFormatter().date(from: dictionary[kDATE] as! String)!
        ownerId = dictionary[kOWNERID] as! String
    }

    func dictionaryFromItem(item: ShoppingList) -> NSDictionary {

        return NSDictionary(objects: [item.name, item.totalPrice, item.totalItems, item.id, dateFormatter().string(from: item.date), item.ownerId], forKeys: [kNAME as NSCopying, kTOTALPRICE as NSCopying, kTOTALITEMS as NSCopying, kSHOPPINGLISTID as NSCopying, kDATE as NSCopying, kOWNERID as NSCopying])

    }

Here is the controller:

import UIKit
import KRProgressHUD


class AllListsViewController: UIViewController, UITableViewDataSource,UITableViewDelegate{


    @IBOutlet weak var tableView: UITableView!

    var allLists:[ShoppingList] = []
    var nameTextField: UITextField!

    override func viewDidLoad() {

        super.viewDidLoad()
        loadLists()

    }

    //MARK: TableView DataSource

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

        return allLists.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)

        let shoppingList = allLists[indexPath.row]

        cell.textLabel?.text = shoppingList.name

        return cell
    }

    //MARK: IBActions


    @IBAction func addBarButonItemPressed(_ sender: Any) {

        let alertController = UIAlertController(title: "Create Shopping List", message: "Enter the shopping list name", preferredStyle: .alert)

        alertController.addTextField{ (nameTextField) in

            nameTextField.placeholder = "Name"
            self.nameTextField = nameTextField
        }

        let cancelAction = UIAlertAction(title: "Cancel", style: .cancel){ (action) in


        }

        let saveAction = UIAlertAction(title: "Save", style: .default){ (action) in

            if self.nameTextField.text != ""{

                self.createShoppingList()

            }else{

                KRProgressHUD.showWarning(message: "Name is empty!")
            }

        }

        alertController.addAction(cancelAction)
        alertController.addAction(saveAction)

        self.present(alertController,animated: true, completion:nil)


    }

    //MARK: LoadList


    func loadLists(){

        //.values has all the info of the child

        firebase.child(kSHOPPINGLIST).child("1234").observe(.value, with: {
            snapshot in

            self.allLists.removeAll()

            //if we actually received smthing from firebase

            if snapshot.exists(){

                let sorted = ((snapshot.value as! NSDictionary).allValues as NSArray).sortedArray(using: [NSSortDescriptor(key: kDATE,ascending: false)])

                for list in sorted {

                    let currentList = list as! NSDictionary

                    self.allLists.append(ShoppingList.init(dictionary: currentList))

                }

            } else {

                print("no snapshot")
            }

            self.tableView.reloadData()

        })


    }


    //MARK: Helper functions

    func createShoppingList(){


        let shoppingList = ShoppingList(_name: nameTextField.text!)

        shoppingList.saveItemInBackground(shoppingList: shoppingList){ (error) in

            if error != nil{

                KRProgressHUD.showError(message: "Error creating shopping list")
                return

            }
        }
    }
}

Also the data formatter is a small function in another file.

import Foundation
import UIKit

private let dateFormat = "yyyyMMDDHHmmss"

func dateFormatter() -> DateFormatter {

    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = dateFormat

    return dateFormatter

}
rmaddy
  • 314,917
  • 42
  • 532
  • 579
leo_bouts
  • 329
  • 2
  • 17
  • Please post just relevant code. – rmaddy May 03 '17 at 01:10
  • And please study http://stackoverflow.com/questions/32170456/what-does-fatal-error-unexpectedly-found-nil-while-unwrapping-an-optional-valu – rmaddy May 03 '17 at 01:12
  • 1
    "I'm trying to find where is the nil when unwrapping" No, you are not trying. Every exclamation mark in your code (`!`) means "please crash me". You cannot complain if that is exactly what happens. All you have to do to find the `nil` is look for it — yourself. Do not use any exclamation marks! Do all your downcasting and your unwrapping of Optionals _safely_ and step through in the debugger to see what's actually happening. – matt May 03 '17 at 01:24
  • @rmaddy i thought they would be helpfull for you to understand what im doing, i also had red the question you are reffering and i was stuck. thank you for your time commenting. – leo_bouts May 03 '17 at 14:11
  • @matt i was trying to safely unwrapp the valuew inside an if but the compiler was complaining that i wasnt initializing all of the values. thank you for your time commenting. – leo_bouts May 03 '17 at 14:11

1 Answers1

1

So you have a forced downcast and a forced optional unwrap on this line:

date = dateFormatter().date(from: dictionary[kDATE] as! String)!

Either your dictionary isn't returning a string, or the string coming out of the dictionary isn't able to be processed as a date. My guess is it's the first problem as dates are often stored as epoch.

Try this instead of the line above. Add a breakpoint at the top and step through:

print(dictionary[kDATE])
if let dictValue = dictionary[kDATE] as? String {
   print(dictValue)
   if let unwrappedDate = dateFormatter().date(from: dictValue) {
       date = unwrappedDate
   }
} 

If it fails on the first if-let then the return value is not a string. If it fails on the second the problem lies with the date formatter being unable to read the format.

The first print might give you a clue as to what type to cast to, the second could help you fix the format.

Try to be careful when force unwrapping,

optionalVar!

or for downcasting.

unknownType as! Type

You should really only "use the force" when you're absolutely sure there's no way the value will be nil.

Donovan King
  • 855
  • 1
  • 6
  • 18