问题
I am creating an iOS app using swift where a user can play music. I have created a struct and an array of the songs that the app offers in a .swift file.
struct Song {
var title: String
var artist: String
var lyrics: String
}
var songs: [Song] = [
Song(title: Song One Title", artist: "Song One Artist", lyrics: ""),
Song(title: Song Two Title", artist: "Song Two Artist", lyrics: "Song Two Lyrics"),
Song(title: Song Three Title", artist: "Song Three Artist", lyrics: ""),
];
The array songs populates a UICollectionViewController and it works great! But, I would like the user to be able to like a song by pressing a button. Then all of the songs that they like would be in another UICollectionViewController. I've been trying multiple scenarios, but all of them have failed, so far. So I decided to come to this community and seek help.
Here's one idea that I had. I would create another variable in the struct, Song, called "liked", and it would be a bool.
struct Song {
var title: String
var artist: String
var lyrics: String
var liked: Bool
}
var songs: [Song] = [
Song(title: Song One Title", artist: "Song One Artist", lyrics: "", liked: false),
Song(title: Song Two Title", artist: "Song Two Artist", lyrics: "Song Two Lyrics", liked: false),
Song(title: Song Three Title", artist: "Song Three Artist", lyrics: "", liked: false),
];
I'm wondering how would I be able to change the bool from false to true for the indexPath of the song that the user liked? I would also like for it to save to UserDefaults so next time the user visists the app, the songs are still liked from previous times. Finally, I would like to display all of the songs in a UICollectionViewController that the bool, liked, is equal to true.
If you have any ideas, it would be GREAT if you could share them! Thanks a lot for the help!
回答1:
I can think of a few approaches
Save liked songs
You can save the all the liked Song objects into UserDefaults. To do this, you need to add a method that converts a Song struct to a [String: Any] i.e. a property list. Then, you can save this [String: Any] to UserDefaults. The downside of this is when the user deletes a song, you will have to delete it from UserDefaults. It is quite difficult to synchronise it.
Save all songs, filter out the liked ones
Instead of saying all the songs like you do in the first approach, you save all the songs and like you attempted, add a liked property. Obviously you will also need a method to convert the struct into a [String: Any].
Store indices of liked songs
Storing entire Song structs might be overkill. If the songs are going to stay in the same order and no more songs will be inserted or deleted, then you can just store the indices of the liked songs. If the user liked the first and third song, you store an array: [1, 3] into UserDefualts.
Core Data
I think this is the best approach among the 4. It might be more difficult to set up the Core Data Stack though. There are lots of tutorials out there talking about how to use Core Data. You will be storing Song entities in Core Data, with a liked property.
回答2:
You shouldn't use UserDefualts for storage. Make it Codable and save it to a json file:
struct Song: Codable {
let title: String
let artist: String
let lyrics: String
var liked: Bool
}
struct Queue: Codable {
var songs: [Song] = []
var data: Data {
return try! JSONEncoder().encode(self)
}
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
var queue = Queue()
queue.songs = [
Song(title: "Song One Title", artist: "Song One Artist", lyrics: "", liked: false),
Song(title: "Song Two Title", artist: "Song Two Artist", lyrics: "Song Two Lyrics", liked: false),
Song(title: "Song Three Title", artist: "Song Three Artist", lyrics: "", liked: false),
]
let preferences = FileManager.default.urls(for: .libraryDirectory, in: .userDomainMask).first!.appendingPathComponent("Preferences", isDirectory: true)
let queueURL = preferences.appendingPathComponent("queue.json")
try! queue.data.write(to: queueURL)
let data = try! Data(contentsOf: queueURL)
let loadedQueue = try! JSONDecoder().decode(Queue.self, from: data)
print(loadedQueue)
}
}
This will print
Queue(songs: [QueuePlayer.Song(title: "Song One Title", artist: "Song One Artist", lyrics: "", liked: false), QueuePlayer.Song(title: "Song Two Title", artist: "Song Two Artist", lyrics: "Song Two Lyrics", liked: false), QueuePlayer.Song(title: "Song Three Title", artist: "Song Three Artist", lyrics: "", liked: false)])
来源:https://stackoverflow.com/questions/47579085/working-with-structs-arrays-and-userdefaults-swift