Search code examples
iosswiftnullnskeyedarchiver

NSKeyedArchiver: key returning nil - Swift


I'm having some issues here. I'm trying to store some information with NSKeyedArchiver, but when I run the app, I get: fatal error: unexpectedly found nil while unwrapping an Optional value.

Apple docs says: "If you invoke one of the decode... methods of this class using a key that does not exist in the archive, a non-positive value is returned. This value varies by decoded type. For example, if a key does not exist in an archive, decodeBoolForKey: returns NO, decodeIntForKey: returns 0, and decodeObjectForKey: returns nil."

My key for decoding the object is returning nil as the docs says, but I have no idea why.

Here is my code:

import UIKit
import CoreData

class MainViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, sendDetailsToMVCDelegate, NSFetchedResultsControllerDelegate, NSCoding {

    @IBOutlet weak var tableView: UITableView!
    var namesListArray:[String] = []
    var imagesListArray:[UIImage] = []

    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.namesListArray = aDecoder.decodeObjectForKey("namesListArray") as! [String] **//HERE IS THE CRASH LINE**
        self.imagesListArray = aDecoder.decodeObjectForKey("imagesListArray") as! [UIImage]
    }

    override func encodeWithCoder(aCoder: NSCoder) {
        aCoder.encodeObject(self.namesListArray, forKey: "namesListArray")
        aCoder.encodeObject(self.imagesListArray, forKey: "imagesListArray")
    }

    override func viewDidLoad() {
        let dir = getUserDir()
        let archive = "\(dir)/iRecipeList-namesListArray"
        if let loaded: AnyObject = NSKeyedUnarchiver.unarchiveObjectWithFile(archive) {
            self.namesListArray = (loaded as? Array)!
        }
    }

    override func viewDidAppear(animated: Bool) {
    }

    func sendDetailsToMVC (name: String, image: UIImage) {

        namesListArray.append(name)
        let dir = getUserDir()
        let archive = "\(dir)/iRecipeList-namesListArray"
        NSKeyedArchiver.archiveRootObject(namesListArray, toFile: archive)

        imagesListArray.append(image)
        tableView.reloadData()
    }

    func getUserDir() -> String {
        let userDir = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)
        return userDir[0] as! String
    }


    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return namesListArray.count
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let row = indexPath.row
        let name = namesListArray[row]
        println("\(row)/")
        let image = imagesListArray[row]
        var cell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: nil)
        cell.textLabel?.text = name
        cell.imageView!.image = image

        return cell
}

    func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
        return true
    }

    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
         func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject) {
            if segue.identifier == "goToInfoVC" {
                if let navigation = navigationController {
                    navigation.popViewControllerAnimated(true)
                }
            }
        }
    }
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if segue.identifier == "newReciep" {
            var vc = segue.destinationViewController as! DetailsViewController
            vc.delegateDetails = self
        }
    }
}

Does anybody have any idea? Thanks in advance!

Error pic

EDIT 1 enter image description here


Solution

  • Change the init to this:

    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        if let namesList = aDecoder.decodeObjectForKey("namesListArray") as? [String] {
            namesListArray = namesList
        } else {
            namesListArray = [String]
        }
        ...
    }