0

My app is crashing with EXC_BAD_INSTRUCTION(code=EXC_i386_INVOP, subcode=0x0). The console logs (lldb). I'm trying to use NSUserDefaults with NSKeyedArchiver and NSKeyedUnarchiver. The class I'm trying to serialise is a subclass of NSManagedObject, so I can't serialise it directly (actually I can, but I can't deserialise it because it needs an NSManagedObjectContext). But actually, if there's a way to serialise the class directly, please say so =)

To solve this problem, I create a NSDictionary with the same properties as the object and then serialise that. Here's how:

    var userDefaults: NSUserDefaults = NSUserDefaults.standardUserDefaults();
    var data: NSData? = userDefaults.dataForKey(DefaultSessionProfileKey);

    // Only saves if necessary
    if data == nil {

        var dict: NSDictionary = [
            "firstName": profile.firstName,
            "lastName": profile.lastName,
            "nameFormat": profile.nameFormat,
            "gender": profile.gender,
            "birthday": profile.birthday,
            "picture": profile.picture,
            "uid": profile.uid
        ];

        // Save the profile to user defaults
        data = NSKeyedArchiver.archivedDataWithRootObject(dict);
        userDefaults.setObject(data, forKey: DefaultSessionProfileKey);
    }

Then to do the opposite. This code crashes on the second line, when retrieving the data from the standard user defaults:

    var userDefaults: NSUserDefaults = NSUserDefaults.standardUserDefaults();
    var data: NSData? = userDefaults.dataForKey(DefaultSessionProfileKey);
    var profile: Profile?;

    if data != nil {

        // Unserialize the profile data. We must serialize/deserialize an NSDictionary instead of directly using a Profile instance because Profile is NSMutableObject, which means that it cannot exist without an NSManagedObjectContext. We don't have one for the serialization/deserialization process, so we generate this dictionary first
        var dict = NSKeyedUnarchiver.unarchiveObjectWithData(data) as NSDictionary;

        if dict != nil {

            // Create the profile instance
            var appDelegate: AppDelegate = UIApplication.sharedApplication().delegate as AppDelegate;
            var entity: NSEntityDescription = NSEntityDescription.entityForName("Profile", inManagedObjectContext: appDelegate.managedObjectContext);

            var profile: Profile = Profile(entity: entity, insertIntoManagedObjectContext: appDelegate.managedObjectContext);

            profile.firstName = dict.objectForKey("first_name") as String;
            profile.lastName = dict.objectForKey("last_name") as String;
            profile.nameFormat = dict.objectForKey("name_format") as String;
            profile.gender = dict.objectForKey("gender") as String;
            profile.birthday = dict.objectForKey("birthday") as NSDate;
            profile.picture = dict.objectForKey("picture") as String;
            profile.uid = dict.objectForKey("uid") as String;
        }

        else {

            // A profile exists in user defaults, but it's not a valid profile, so we take the chance to clean up
            userDefaults.removeObjectForKey(DefaultSessionProfileKey);
        }
    }
rmaddy
  • 314,917
  • 42
  • 532
  • 579
André Fratelli
  • 5,920
  • 7
  • 46
  • 87

1 Answers1

0

NSUserDefaults.dataForKey returns an implicitly unwrapped optional. Try changing your second line NSData? to NSData!, or removing the type altogether.

Also, typically when using NSKeyedArchiver, you should save to disk instead of NSUserDefaults. Defaults is a key/value store, so theres no need to archive it into one key, simply save the data with data.writeToFile()

Matthew Knippen
  • 1,048
  • 9
  • 22