swiftnsobjectnscodinguserdefaults

"Value for key 'root' was unexpected class 'NSArray'" error when retrieve an array of object in UserDefault, Swift


I'm trying to retrieve an array of custom object in Swift, where i get the error

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

My project is a music player, so I'm having a Song object and a Playlist object, which will have a name and list song songs.

I've already encode the object model:

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")
    }
}

Storing the playlists:

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)")
            }

And retrieving it:

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)")
        }

Full error description:

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

Can anyone show me if I'm missing something. Many thanks!


Solution

  • I don't know why but changing from

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

    to

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

    will fix the issue for me. So I will close my ticket here. Thank you if you're noticing!