Encoding/Decoding not working on Dictionary Objects

I cannot seem to find the answer to this problem. Hopefully someone here will be able to help.


I'm trying to Encode/Decode an object in order to store it in UserDefaults. My object contains a Dictionary object contining a key, with an array of user-defined objects. No matter what I do or try i cannot get the encoder to encode the Dictionary object. All other properties encode/decode without issue.


All members of the MyUserDefinedClass are basic types and have encode/decode methods that work without issue.


I've tried everything I can think of trying to get this to work ... breaking it down by parts; Keys and Values ... nothing works.


Any help would be "Greatly" appreicated



Swift Code example:


@objc func encodeWithCoder(aCoder: NSCoder)

{

// Other objects encoded here


if let myDictionary = self.myDictionaryObject

{

// gives me an error that cannot encodeObject with myDictionaryObject type

aCoder.encodeObject(myDictionary, forKey: "myDictionaryObject")

}

}



@objc required init(coder aDecoder: NSCoder)

{


// other objects decoded here


// This compiles with no error or warning

self.myDictionaryObject = aDecoder.decodeObjectForKey("myDictionaryObject") as? Dictionary

}



// myDictionaryObject

var myDictionaryObject = Dictionary<Int, [MyUserDefinedClass]>!


Thanks, Gary

Replies

I'm not able to repeat your problem. I haven't used archivers before, but here is the code I used. What are you trying to do that is different from what I'm doing?


class MyUserDefinedClass : NSObject {
    let a : Int

    init(a:Int) {
        self.a = a
    }

    @objc required init(coder aDecoder: NSCoder) {
        self.a = aDecoder.decodeObjectForKey("a") as! Int
    }

    @objc func encodeWithCoder(aCoder: NSCoder) {
        aCoder.encodeObject(a, forKey: "a")
    }

    override var description: String {
        return "\(a)"
    }
}

class Foo : NSObject {
    var myDictionary : Dictionary<Int, [MyUserDefinedClass]>!

    override init() {
        myDictionary = [:]
        myDictionary[0] = [MyUserDefinedClass(a:2)]
        myDictionary[1] = [MyUserDefinedClass(a:3)]
    }

    @objc required init(coder aDecoder: NSCoder) {
        self.myDictionary = aDecoder.decodeObjectForKey("myDictionaryObject") as? Dictionary
    }

    @objc func encodeWithCoder(aCoder: NSCoder) {
        aCoder.encodeObject(myDictionary, forKey: "myDictionaryObject")
    }
}

let foo = Foo()

let archived = NSKeyedArchiver.archivedDataWithRootObject(foo)

let foo2 = NSKeyedUnarchiver.unarchiveObjectWithData(archived)

print(foo.myDictionary) // prints [0: [2], 1: [3]]

print(foo2?.myDictionary) // prints Optional([0: [2], 1: [3]])

Thanks for your reply ...


last night I finally determined what was going on. Xcode 6.4 actually gave me a more verbose error message which helped.


It turns out that I was using a struct as the object type in the dictionary. Even though you can implement the NSCoding protocol in a struct, you cannot inherient from NSObject. I changed the object type to a class, inherited NSObject, and updated the misc syntax changes in the protocol, and now everything works fine.


Very odd .. it's things such as this that make using a new language interested 🙂


Again, thanks for your reply.


-gary

A good example of why naming things correctly is so crucial. In your OP you said the dictionary contained "MyUserDefinedClass" when it sounds like it wasn't a class at all. It would be hard for anyone to guess the problem given that misleading bit of info.

Actually it was a Class .. in the class I had two Dictionary Object, each one contained an <key,[Object]> .. it was those objects that were a struct. Sorry that I didn't make that clear.


thanks,

-gary