В приведенном ниже TableViewController я пытаюсь сохранить массив типа класса (playList) в UserDefaults, а затем получить его в каждой ячейке таблицы. Но при открытии этого представления таблицы происходит сбой приложения с сообщением «Завершение работы приложения из-за необработанного исключения« NSInvalidArgumentException», причина: «Попытка вставить объект списка, не являющийся свойством ( " LocalMusicPlayer.SongData" ) для ключа playList'", но если данные представляют собой просто массив строк, это работает.
Просто зайдите на UserDefaults
сегодня, хотите спросить, не поддерживается ли он для хранения данных типа класса или должен быть задействован какой-то дополнительный метод, такой как defaults.object(forKey: "playList")
?
Другой вопрос заключается в том, что в реальной реализации, если я должен поставить инициализацию UserDefaults
операций в init() некоторых других файлов, но не в viewDidLoad() представления. Ваша помощь приветствуется!
/// Ну, ниже мой файл SongData и TableView.
/// 9.4, 2019, задействуем NSObject и NSCoding, сейчас работает.
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
}
}
/// Табличное представление
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
}
}
Data
. Поскольку экземплярUIImage
включен, я бы рекомендовал сделать класс подклассомNSObject
, принятьNS(Secure)Coding
и реализовать методы протокола. Это описано в дубликате. Здесь много других связанных вопросов - person vadian   schedule 03.09.2019NSObject
иNSCoding
для своего класса SongData и реализую методы протокола, теперь он работает, я могу получить название песни, обложку... из декодера . Всего 1 вопрос, идеально ли сохранять обложку музыки вUserDefaults
?Например, сотни песен с обложкой могут занимать большой размер, если быUserDefaults
могла нормально с этим справиться и не повлиять на производительность приложения? - person ChuckZHB   schedule 04.09.2019UserDefaults
для больших наборов данных — плохая практика. Есть CoreData, MYSQL или другие сторонние базы данных. - person vadian   schedule 04.09.2019