Reputation: 1603
I have a Swift dictionary with keys as Strings and values as Swift tuples. I would like to send this dictionary over to the other device so I need to implement NSCoding on this dictionary. Can anybody help me as to how can I achieve that. Following is my dictionary code.
class STCTruthDict: NSObject, NSCoding, SequenceType {
typealias IpRelationshipTuple = (String, String?)
private var truthDict: [String : IpRelationshipTuple] = [ : ]
subscript(key: String) -> IpRelationshipTuple? {
get {
return self.truthDict[key]
}
set {
truthDict[key] = newValue
}
}
// MARK: - Initializers
override init() {
super.init()
}
required init(coder aDecoder: NSCoder) {
self.truthDict = aDecoder.decodeObjectForKey("truthDict") as! [String : IpRelationshipTuple]
let key = aDecoder.decodeObjectForKey("user_id") as? String
let ip = aDecoder.decodeObjectForKey("tupleIp") as? String
let groupId = aDecoder.decodeObjectForKey("tupleGroupId") as? String
}
func encodeWithCoder(aCoder: NSCoder) {
for (key, tuple) in self.truthDict {
aCoder.encodeObject(key, forKey: "user_id")
aCoder.encodeObject(tuple.Ip, forKey: "tupleIp")
aCoder.encodeObject(tuple.groupId, forKey: "tupleGroupId")
}
}
func generate() -> DictionaryGenerator <String, IpRelationshipTuple> {
return self.truthDict.generate()
}
}
Upvotes: 3
Views: 3129
Reputation: 12868
The problem you are running into is that tuples are structs
and not class
(object) types. You'll notice this issue when you try to do the following:
if let dictionary = aDecoder.decodeObjectForKey("truthDict") as? [String : RelationshipType] { ... }
This issues unfortunately comes up a bit when trying to deal with value types in Swift. To get around this limitation, you can box your value types using a generic Box
class like so:
class Box<T>
{
var value : T?
init(_ value: T?)
{
self.value = value
}
}
With the Box
class, you can use this to encode and decode your dictionary tuples:
class TruthDictionary : NSObject, NSCoding, SequenceType
{
typealias RelationshipType = (ip: String, groupId: String?)
private var dictionary = [String : RelationshipType]()
subscript(key: String) -> RelationshipType?
{
get { return self.dictionary[key] }
set { self.dictionary[key] = newValue }
}
// MARK: - Initializers
override init()
{
super.init()
}
// MARK: - NSCoding
required init(coder aDecoder: NSCoder)
{
// Unbox each tuple from the decoded dictionary
if let boxedDictionary = aDecoder.decodeObjectForKey("truthDict") as? [String : Box<RelationshipType>]
{
for (key, boxedTuple) in boxedDictionary
{
self.dictionary[key] = boxedTuple.value
}
}
}
func encodeWithCoder(aCoder: NSCoder)
{
var boxedDictionary = [String: Box<RelationshipType>]()
// Box each tuple to the dictionary to be encoded
for (key, tuple) in self.dictionary
{
boxedDictionary[key] = Box(tuple)
}
aCoder.encodeObject(boxedDictionary, forKey: "truthDict")
}
// MARK: - SequenceType
func generate() -> DictionaryGenerator<String, RelationshipType>
{
return dictionary.generate()
}
}
Upvotes: 4