laurie
laurie

Reputation: 1015

Exception when saving object with NSCoding Swift

I'm having some problems when trying to save/archive an object using NSCoding. I essentially have a class QA which defines a question and answer, I also have a class Volume which contains several attributes including an array of QA objects.

The error occurs when the NSKeyedArchiver.archiveRootObject method is called. My suspicion is that it is to do with the array of QA objects because if I comment out that part the exception isn't thrown.

My Volume class inherits from NSObject and NSCoding and the QA object inherits from NSObject only.

The exception thrown is: ...encodeWithCoder:]: unrecognized selector sent to instance 0x600000077c80

The method being used to archive is:

static func save() {
    print("starting save...")
    let DocumentsDirectory = FileManager().urls(for: .documentDirectory, in: .userDomainMask).first!
    let ArchiveURL = DocumentsDirectory.appendingPathComponent("volumesData")
    NSKeyedArchiver.archiveRootObject(VolumeTableViewController.volumesArray, toFile: ArchiveURL.path)
    print("Ending save...")
}

My Volume class is:

import Foundation
class Volume: NSObject, NSCoding {
    let volumeNumber: Int
    var completed: Bool
    var questionsData: [QA]

    init (volumeNumber: Int, completed: Bool, questionsData: [QA]) {
        self.volumeNumber = volumeNumber
        self.completed = completed
        self.questionsData = questionsData
    }

    // MARK: NSCoding
    public convenience required init?(coder aDecoder: NSCoder) {

        let volumeNumber = aDecoder.decodeObject(forKey: "volumeNumber") as! Int
        let completed = aDecoder.decodeObject(forKey: "completed") as! Bool
        let questionsData = aDecoder.decodeObject(forKey: "questionsData") as! [QA]

        self.init(volumeNumber: volumeNumber, completed: completed, questionsData: questionsData)
    }

    func encode(with aCoder: NSCoder) {
        aCoder.encode(volumeNumber, forKey: "volumeNumber")
        aCoder.encode(completed, forKey: "completed")
        aCoder.encode(questionsData, forKey: "questionsData")
    }
}

And my QA class is:

 import Foundation
class QA: NSObject {
    let questionsText: String
    let answerText: [String]
    let correctAnswer: [Bool]
    var selectedAnswer: [Bool?]


    // Create standard initiator
    init(questionsText:String, answerText: [String], correctAnswer: [Bool], selectedAnswer: [Bool?]) {
        self.questionsText = questionsText
        self.answerText = answerText
        self.correctAnswer = correctAnswer
        self.selectedAnswer = selectedAnswer
    }
} 

Any thoughts?

Upvotes: 0

Views: 381

Answers (1)

Ellen
Ellen

Reputation: 5190

QA should also adopt NSCoding.All the custom properties of an object should be archivable as per rule every object in your object's object graph also conforms to NSCoding.

Use Codable protocol for Swift 4.

Upvotes: 2

Related Questions