In below TableViewController, I'm trying to store a class type array(playList) to UserDefaults then retrieve it in each table cell. But as opening this table View, app is crashed with `"Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Attempt to insert non-property list object ( "LocalMusicPlayer.SongData" ) for key playList'", but if the data is simply string array, it works.
Just come to UserDefaults
today, want to ask if it is not supported for storing class type data or some extra method like defaults.object(forKey: "playList")
should be involved?
Another question is that in real implementation, if I should put initialization of UserDefaults
operations to some other files' init() but not under viewDidLoad() of a View. Your help is appreciated!
/// Well, below is my SongData and TableView file.
/// 9.4, 2019, involve NSObject and NSCoding, it is working now.
import UIKit
class SongData: NSObject, NSCoding {
var songName: String
var artistName: String
var albumName: String
var albumArtwork: UIImage
var url: URL
init(songName: String, artistName: String, albumName: String, albumArtwork: UIImage, url: URL) {
self.songName = songName
self.artistName = artistName
self.albumName = albumName
self.albumArtwork = albumArtwork
self.url = url
}
// MARK: -NSCoding
func encode(with aCoder: NSCoder) {
aCoder.encode(songName, forKey: "songName")
aCoder.encode(artistName, forKey: "artistName")
aCoder.encode(albumName, forKey: "albumName")
aCoder.encode(albumArtwork, forKey: "albumArtwork")
aCoder.encode(url, forKey: "url")
}
required init?(coder aDecoder: NSCoder) {
songName = aDecoder.decodeObject(forKey: "songName") as! String
artistName = aDecoder.decodeObject(forKey: "artistName") as! String
albumName = aDecoder.decodeObject(forKey: "albumName") as! String
albumArtwork = aDecoder.decodeObject(forKey: "albumArtwork") as! UIImage
url = aDecoder.decodeObject(forKey: "url") as! URL
}
}
/// Table View
import UIKit
class PlaylistTableViewController: UITableViewController {
var song: SongData?
var playList = [SongData]()
let defaults = UserDefaults.standard
override func viewDidLoad() {
super.viewDidLoad()
playList.append(SongData(songName: "You Belong With Me", artistName: "Tylor Swift", albumName: "Love", albumArtwork: UIImage(named: "Apple")!, url: URL(fileURLWithPath: "file:///private/var/mobile/Containers/Data/Application/14E1BC3D-65A6-4854-9CD6-A8740265F341/Documents/Just%20Dance.mp3")))
playList.append(SongData(songName: "Just Dance", artistName: "Lady Gaga", albumName: "Love", albumArtwork: UIImage(named: "Apple")!, url: URL(fileURLWithPath: "file:///private/var/mobile/Containers/Data/Application/14E1BC3D-65A6-4854-9CD6-A8740265F341/Documents/Just%20Dance.mp3")))
let encodedData = try! NSKeyedArchiver.archivedData(withRootObject: playList, requiringSecureCoding: false)
defaults.set(encodedData, forKey: "playList")
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return playList.count
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return "PLAYLISTS"
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "playListLabelCell", for: indexPath)
let decoded = defaults.object(forKey: "playList") as! Data
let decodedTeams = try! NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(decoded) as! [SongData]
cell.textLabel?.text = decodedTeams[indexPath.row].songName
cell.detailTextLabel?.text = decodedTeams[indexPath.row].artistName
cell.imageView?.image = decodedTeams[indexPath.row].albumArtwork
return cell
}
}