Значение для ключа «root» было неожиданной ошибкой класса «NSArray» при извлечении массива объектов в UserDefault, Swift

Я пытаюсь получить массив пользовательских объектов в Swift, где я получаю сообщение об ошибке

"UserInfo={NSDebugDescription=value for key 'root' was of unexpected class 'NSArray'. Allowed classes are '{(MusicCloud.Playlist)}"

Мой проект представляет собой музыкальный проигрыватель, поэтому у меня есть объект Song и объект Playlist, который будет иметь имя и список песен.

Я уже закодировал объектную модель:

class Playlist: NSObject, NSCoding{
    var name: String
    var songs: [Song]
    var image: UIImage

    override init() {
        self.name = ""
        self.songs = []
        self.image = UIImage()
    }

    init(name: String, songs: [Song], image: UIImage) {
        self.name = name
        self.songs = songs
        self.image = image
    }

    required convenience init(coder aDecoder: NSCoder) {
        let name = aDecoder.decodeObject(forKey: "name") as! String
        let songs = aDecoder.decodeObject(forKey: "songs") as! [Song]
        let image = aDecoder.decodeObject(forKey: "photo") as! UIImage
        self.init(name: name, songs: songs, image: image)
    }

    func encode(with aCoder: NSCoder) {
        aCoder.encode(name, forKey: "name")
        aCoder.encode(songs, forKey: "songs")
        aCoder.encode(image, forKey: "photo")
    }
}

Хранение плейлистов:

let playlist: Playlist = Playlist(name: txt.text!, songs: [], image: UIImage())
            MusicService.shared.playlists.append(playlist)
            do{
                let encodedData: Data = try NSKeyedArchiver.archivedData(withRootObject: MusicService.shared.playlists, requiringSecureCoding: false)
                self.userDefaults.set(encodedData, forKey: "playlist")
                self.userDefaults.synchronize()
            }catch let error{
                print("error when add  \(error)")
            }

И получение его:

do{
            let decodedPlaylists = try NSKeyedUnarchiver.unarchivedObject(ofClasses: [Playlist.self], from: decoded!) as! [Playlist]
            print("here is decoded playlist: \(decodedPlaylists)")
            MusicService.shared.playlists = decodedPlaylists
        }catch let error{
            print("error when retrieve \(error)")
        }

Полное описание ошибки:

Domain=NSCocoaErrorDomain Code=4864 "value for key 'root' was of unexpected class 'NSArray'. Allowed classes are '{(
    MusicCloud.Playlist
)}'."

Может ли кто-нибудь показать мне, если я что-то упустил. Большое спасибо!


person hrtlkr29    schedule 20.05.2019    source источник
comment
Вы не должны использовать NSCoding, вместо этого используйте Codable.   -  person Dávid Pásztor    schedule 20.05.2019
comment
@DávidPásztor, можешь подробнее объяснить? Я новичок в таком локальном хранилище, большое спасибо   -  person hrtlkr29    schedule 20.05.2019
comment
См. этот и этот ответ на как этого добиться. NSCoding — это устаревший способ сохранения пользовательских объектов в файловой системе, а Codable — это новое, чистое решение Swift, которое более безопасно для типов, поэтому вам следует использовать его вместо устаревшего решения.   -  person Dávid Pásztor    schedule 20.05.2019
comment
@DávidPásztor Я посмотрю. Большое спасибо!   -  person hrtlkr29    schedule 20.05.2019


Ответы (2)


Я не знаю, почему, но переход от

let decodedPlaylists = try NSKeyedUnarchiver.unarchivedObject(ofClasses: [Playlist.self], from: decoded!) as! [Playlist]

to

let decodedPlaylists = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(decoded!) as! [Playlist]

решит проблему для меня. Так что я закрою свой билет здесь. Спасибо, если заметили!

person hrtlkr29    schedule 20.05.2019

попробуй это

let decodedPlaylists = try NSKeyedUnarchiver.unarchivedObject(ofClasses: [Playlist.self, NSArray.self], from: decoded!) as! [Playlist]

Наверное,

следующий код декодирования содержит структуру данных NSArray

let songs = aDecoder.decodeObject(forKey: "songs") as! [Song]
person black_pearl    schedule 12.04.2020