0

I am receiving this error after my App Delegate crashes.

2016-11-17 10:01:34.780 Foodie[38429:3212774] * Terminating app due to uncaught exception 'NSInvalidUnarchiveOperationException', reason: '* -[NSKeyedUnarchiver decodeObjectForKey:]: cannot decode object of class (Photomania.Item) for key (NS.objects); the class may be defined in source code or a library that is not linked'

How can I fix it?

Here is my App Delegate:

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

var window: UIWindow?

// Override point for customization after application launch.

//Create an ImageStore
//let imageStore = ImageStore()
//let itemStore = ItemStore()

//Access the ItemsViewController and set its item store
//let navController = window!.rootViewController as! UINavigationController
//let itemsController = navController.topViewController as! ItemsViewController

//itemsController.itemStore = itemStore
//itemsController.imageStore = imageStore

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

    let rootController = window?.rootViewController

    if rootController is UITabBarController {
        let firstTabItem = (rootController as! UITabBarController).viewControllers?[0]

        if firstTabItem is UINavigationController {

            let firstController = (firstTabItem as! UINavigationController).viewControllers.first as! ItemsViewController
            firstController.itemStore  = ItemStore()
            firstController.imageStore = ImageStore()
        }
    }
    return true
}

func applicationWillResignActive(application: UIApplication) {
}

func applicationWillEnterForeground(application: UIApplication) {
}

func applicationDidBecomeActive(application: UIApplication) {
}

func applicationWillTerminate(application: UIApplication) {
}

func applicationDidEnterBackground(application: UIApplication) {
 }
}

Here is Photomania.Item.swift :

     import UIKit

    class Item: NSObject, NSCoding {
       var meal: String
       var restaurantName: String?
       var valueInDollars: Int
       let dateCreated: NSDate
       let itemKey: String

func encodeWithCoder(aCoder: NSCoder) {
    aCoder.encodeObject(meal, forKey: "meal")
    aCoder.encodeObject(dateCreated, forKey: "dateCreated")
    aCoder.encodeObject(itemKey, forKey: "itemKey")
    aCoder.encodeObject(restaurantName, forKey: "restaurantName")

    aCoder.encodeInteger(valueInDollars, forKey: "valueInDollars")
}

required init(coder aDecoder: NSCoder) {
    meal = aDecoder.decodeObjectForKey("meal") as! String
    dateCreated = aDecoder.decodeObjectForKey("dateCreated") as! NSDate
    itemKey = aDecoder.decodeObjectForKey("itemKey") as! String
    restaurantName = aDecoder.decodeObjectForKey("restaurantName") as! String?

    valueInDollars = aDecoder.decodeIntegerForKey("valueInDollars")

    super.init()
 }

init(meal: String, restaurantName: String, valueInDollars: Int) {
    self.meal = meal
    self.restaurantName = restaurantName
    self.valueInDollars = valueInDollars
    self.dateCreated = NSDate()
    self.itemKey = NSUUID().UUIDString

    super.init()
 }

convenience init(random: Bool = false) {
    self.init(meal: "Meal", restaurantName: "Restaurant", valueInDollars: 0)
 }
}

Item Store:

import UIKit

class ItemStore {

var allItems = [Item]()

let itemArchiveURL: NSURL = {
    let documentsDirectories =
        NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains:  .UserDomainMask)
    let documentDirectory = documentsDirectories.first!
    return documentDirectory.URLByAppendingPathComponent("items.archive")
} ()

func createItem() -> Item {
    let newItem = Item(random: true)

    allItems.append(newItem)

    return newItem
}

func removeItem(item: Item) {
    if let index = allItems.indexOf(item) {
        allItems.removeAtIndex(index)
    }
}
func moveItemAtIndex(fromIndex: Int, toIndex: Int) {
    if fromIndex == toIndex {
        return
    }
    let movedItem = allItems[fromIndex]
    allItems.removeAtIndex(fromIndex)
    allItems.insert(movedItem, atIndex: toIndex)
}
func saveChanges() -> Bool {
    print("Saving items to: \(itemArchiveURL.path!)")
    return NSKeyedArchiver.archiveRootObject(allItems, toFile: itemArchiveURL.path!)
}
init() {
    if let archivedItems =
        NSKeyedUnarchiver.unarchiveObjectWithFile(itemArchiveURL.path!) as? [Item] {
            allItems += archivedItems
    }
}
func imageURLForKey(key: String) -> NSURL {
    let documentsDirectories = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
    let documentDirectory = documentsDirectories.first!

    return documentDirectory.URLByAppendingPathComponent(key)
 }
}
saroj raut
  • 834
  • 8
  • 16
Allie
  • 57
  • 7
  • Can you tell us more about what a `Photomania.Item` is and how it's defined/used? – Phillip Mills Nov 17 '16 at 15:11
  • 1
    you need to post your appdelegate and other relevant code to get answers – Will Evers Nov 17 '16 at 15:11
  • have you implemented the NSCoding protocol ? – Matthias Nov 17 '16 at 15:14
  • @PhillipMills Please see my updated code. I added the App Delegate and Photomania.Item – Allie Nov 24 '16 at 22:10
  • @WillEvers Please see my updated question. I added the App Delegate code – Allie Nov 24 '16 at 22:10
  • @Matthias I added my App Delegate Code. I am not sure what the NSCoding protocol is, but I think I did it. – Allie Nov 24 '16 at 22:11
  • @Allie Yes you did :) It's about implementing init?(coder aDecoder: NSCoder) and encode(with aCoder: NSCoder). If for restaurantName you put aDecoder.decodeObject(forKey: "restaurantName") as? String instead o f aDecoder.decodeObjectForKey("restaurantName") as! String?, does it change something ? – Matthias Nov 24 '16 at 23:04
  • @Matthias That gives me an error: "Extra argument forKey in call" – Allie Nov 25 '16 at 20:21
  • Oh sorry you don't use swift3, try aDecoder.decodeObjectForKey("restaurantName") as? String – Matthias Nov 25 '16 at 20:23
  • @Matthias I still received the crash error: "Terminating app due to uncaught exception 'NSInvalidUnarchiveOperationException', reason: '*** -[NSKeyedUnarchiver decodeObjectForKey:]: cannot decode object of class (Photomania.Item) for key (NS.objects); the class may be defined in source code or a library that is not linked' " Any other ideas? – Allie Nov 26 '16 at 23:06
  • what is the line of code used to archive the object, and the one to unarchive it ? – Matthias Nov 26 '16 at 23:43
  • Which object? @Matthias – Allie Nov 27 '16 at 16:35
  • @Matthias I added my ItemStore code where I unarchive and archive. – Allie Nov 27 '16 at 16:37
  • @Allie Using your code I was able to create a store, create items, save changes. Then I closed the app, reopened it. tried the same actions and it worked again..So right now I have no clue what is wrong. My guess is that at some point you save an object with a missing value. Try to add an exception breakpoint to your project if it's not already done. http://stackoverflow.com/questions/17802662/exception-breakpoint-in-xcode. After that you might be able to see exactly what line is causing the crash – Matthias Nov 27 '16 at 17:43
  • @Matthias I found the line! It is in ItemStore. It is "NSKeyedUnarchiver.unarchiveObjectWithFile(itemArchiveURL.path!) as? [Item] { " at the very bottom of my ItemStore code. What is wrong with this line? – Allie Nov 27 '16 at 20:48

0 Answers0