I got the following codes on writing an object named Packet and send to the other side through Multipeer connectivity. However, I got the following error whenever it try to decode the encoded object.
class Packet : NSObject, NSCoding {
var tmp1: Double = 0
var tmp2: Double = 0
struct PropertyKey {
static let tmp1Key = "tmp1Key"
static let tmp2Key = "tmp2Key"
}
init(tmp1: Double, tmp2: Double) {
self.tmp1 = tmp1
self.tmp2 = tmp2
super.init()
}
deinit {
}
required convenience init(coder aDecoder: NSCoder) {
debugPrint("initcoder")
let tmp1 = aDecoder.decodeObject(forKey: PropertyKey.tmp1Key) as! Double // crash here
let tmp2 = aDecoder.decodeObject(forKey: PropertyKey.tmp2Key) as! Double
self.init(tmp1: tmp1, tmp2: tmp2)
}
public func encode(with aCoder: NSCoder) {
debugPrint("encodeCoder")
aCoder.encode(tmp1, forKey: PropertyKey.tmp1Key)
aCoder.encode(tmp2, forKey: PropertyKey.tmp2Key)
}
}
The error I got is ---- Print out from me ---- "initcoder" fatal error: unexpectedly found nil while unwrapping an Optional value 2016-09-30 13:32:55.901189 Connection[323:33022] fatal error: unexpectedly found nil while unwrapping an Optional value
But when I construct the object, all the values are set. I contracted a Packet object with no problem.
---- Additional information ------ I used the following codes for encode and decode the data when send to the other side through multiplier connectivity.
func dataForPacket(packet: Packet) -> Data {
let data = NSMutableData()
let archiver = NSKeyedArchiver(forWritingWith: data)
archiver.encode(packet, forKey: "Packet")
archiver.finishEncoding()
debugPrint("dataForPacket \(data) \(packet)")
return data as Data
}
func packetForData(_ data: Data) -> Packet {
debugPrint("packetForData")
let unarchiver = NSKeyedUnarchiver(forReadingWith: data)
let packet: Packet = unarchiver.decodeObject(forKey: "Packet") as! Packet
// crash here (as this will call the init of the Packet class)
debugPrint("packetForData \(packet)")
return packet
}
I wonder what can cause the error. Thanks.
Swift 3:
I was encoding a double value. Use decoder.containsValue to check if a value was encoded.
And use decodeDouble(forKey:). Not decodeObject(forKey:)
var dateTime: TimeInterval = SOME_TIME_INTERVAL (Double)//Can be saved(encoded) previously, and not encoded as well.
aCoder.encode(dateTime, forKey: "dateTime")
if decoder.containsValue(forKey: "dateTime") {
dateTime = decoder.decodeDouble(forKey: "dateTime")
}
Swift 4.2:
When using decodeObject(forKey:)
to decode primitive types, it returns nil. Because the overload of encode(_:forKey:)
takes an Int directly and writes it NSNumber type, and you cannot decode it as an object.
decodeInteger(forKey:)
reads it out as an Int properly and returns it.
You can use decodeInteger(forKey:)
, Int(decodeInt32(forKey:))
or Int(decodeInt64(forKey:))
instead.
When encoding or decoding primitive types such as Double and Bool you must use the designated methods decodeDouble:forKey
and decodeBool:forKey
respectively otherwise they will fail to decode and return nil.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With