I know that there are several questions similar to this, that tend to all revolve around the class not conforming to the protocol properly, but that should not be the immediate issue here.
The following is a condensed version of the code that is currently giving me this problem:
enum Binary: Int {
case a = 0
case b = 1
case c = 9
}
final class MyClass: NSCoder {
var string: String?
var date: Date?
var binary: Binary = .c
override init() { }
enum CodingKeys: CodingKey {
case string, date, binary
}
}
extension MyClass: Codable {
convenience init(from decoder: Decoder) throws {
self.init()
let values = try decoder.container(keyedBy: CodingKeys.self)
string = try values.decode(String.self, forKey: .string)
date = try values.decode(Date.self, forKey: .date)
binary = try Binary(rawValue: values.decode(Int.self, forKey: .binary)) ?? .c
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(string, forKey: .string)
try container.encode(date, forKey: .date)
try container.encode(binary.rawValue, forKey: .binary)
}
}
I have created the following class which then attempts to call MyClass
with the purpose of writing & reading it to UserDefaults
:
class MyClassController {
private let myClass: MyClass
init() {
self.myClass = MyClass()
self.myClass.string = "string"
self.myClass.date = Date()
self.myClass.binary = .a
}
func writeMyClass() {
let encodedData = NSKeyedArchiver.archivedData(withRootObject: myClass)
UserDefaults.standard.set(encodedData, forKey: String(describing: MyClass.self))
}
func readMyClass() {
if let decoded = UserDefaults.standard.object(forKey: String(describing: MyClass.self)) as? Data,
let myClass = NSKeyedUnarchiver.unarchiveObject(with: decoded as Data) as? MyClass {
print("string: \(myClass.string ?? "nil") date: \(myClass.date ?? Date()) binary: \(myClass.binary)")
}
}
}
As soon as I call the writeMyClass function though, I get this error:
[DemoDecoder.MyClass encodeWithCoder:]: unrecognized selector sent to instance #blahblah#
Two things I have also tried:
func encode(with aCoder: NSCoder)
to MyClass
MyClass
& CodingKeys
and the init/encode functionsYou have a lot of mismatched attempts and various encoding/decoding mechanisms.
NSKeyedArchiver
and NSKeyedUnarchiver
require that all involved types conform to the NSCoding
protocol. This is the older mechanism from the Objective-C frameworks.
The protocols Codable
, Encoder
, and Decoder
are new to Swift 4. Such data types should be used with Swift encoder and decoders such as JSONEncoder
and JSONDecoder
or PropertyListEncoder
and PropertyListDecoder
.
I suggest you remove the reference to NSCoder
and remove the uses of NSKeyedArchiver
and NSKeyedUnarchiver
. Since you have implemented the Codable
protocol, use an appropriate Swift encoder and decoder. In your case you want to use PropertyListEncoder
and PropertyListDecoder
.
Once that is done you should probably change MyClass
to be a struct
instead of a class
.
You should also avoid use UserDefaults
to store data. Write the encoded data to a plist file instead.
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