Невозможно архивировать вложенные пользовательские объекты с помощью NSCoding

У меня есть следующая архитектура данных, где Orchestra имеет много Section, а каждый Section имеет много Player:

введите здесь описание изображения

Все 3 класса соответствуют протоколу NSCoding и имеют необходимые реализованные методы. Согласно этому вопросу SO, он должен работать, поскольку NSCoding работает рекурсивно.

Внутри одноэлементного класса Orchestra у меня есть следующие методы для сохранения и извлечения Sections:

let sectionArchivalURL: URL = {

    let documentDirectories = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
    let documentDirectory = documentDirectories.first!

    return documentDirectory.appendingPathComponent("sections.archive") //gets archived Player objects
} ()

func saveChanges() -> Bool {
    print ("Saving sections to: \(sectionArchivalURL.path)")
    return NSKeyedArchiver.archiveRootObject(allSections, toFile: sectionArchivalURL.path)
}

Section также соответствует NSCoding:

//MARK: - NSCoding methods
func encode(with aCoder: NSCoder) {
    aCoder.encode(sectionName, forKey: "sectionName")
    aCoder.encode(allPlayers, forKey: "allPlayers")
}

required init(coder aDecoder: NSCoder) {

    sectionName = aDecoder.decodeObject(forKey: "sectionName") as! String
    allPlayers = aDecoder.decodeObject(forKey: "allPlayers") as! [Player]

    super.init()
}

Точно так же Player также соответствует NSCoding:

//MARK: - NSCoding methods
func encode(with aCoder: NSCoder) {
    aCoder.encode(name, forKey: "playerName")        
    print ("encoding Player") //does not get called
}

required init(coder aDecoder: NSCoder) {

    name = aDecoder.decodeObject(forKey: "playerName") as! String
    super.init()
}

Сохранение подтверждено рабочим. Однако, когда приложение перезапускается, я могу просматривать свои команды, но содержащие Players пусты. Я также знаю, что функция кодирования в Player не вызывалась. Что я делаю неправильно?


person daspianist    schedule 03.04.2017    source источник
comment
Ошибка говорит о том, что у вас есть массив, соответствующий ключу allPlayers, но вы пытаетесь сделать его одним объектом Player.   -  person Phillip Mills    schedule 03.04.2017
comment
@PhillipMills отличное понимание - спасибо. Исправление помогло избавиться от ошибки, но теперь не отображаются Player.   -  person daspianist    schedule 03.04.2017


Ответы (1)


Оставьте все как есть, кроме вашего класса Player. Вот как я заработал:

    func encode(with aCoder: NSCoder) {
        let encName = NSKeyedArchiver.archivedData(withRootObject: name)
        aCoder.encode(encName, forKey: "playerName")        
        print ("encoding Player")
    }

    required init(coder aDecoder: NSCoder) {
        let tmpName = aDecoder.decodeObject(forKey: "playerName")
        name = NSKeyedUnarchiver.unarchiveObject(with: tmpName as! Data) as! String
    }
person Antoine Saliba    schedule 26.07.2017