У меня есть отношение «один ко многим» в CoreData, которое представляет собой один список воспроизведения для многих песен, песни представляют собой упорядоченный набор в основном классе данных, и я сохраняю атрибут позиции с каждой песней, чтобы отслеживать порядок. Вот как я это реализовал:
Класс плейлиста:
extension Playlist {
@nonobjc public class func fetchRequest() -> NSFetchRequest<Playlist> {
return NSFetchRequest<Playlist>(entityName: "Playlist")
}
@NSManaged public var name: String?
@NSManaged public var numberOfSongs: Int16
@NSManaged public var songs: NSOrderedSet?
public var songsArray: [Song] {
if let set = self.songs{
let array = set.sortedArray { (song1, song2) -> ComparisonResult in
guard let s1 = song1 as? Song, let s2 = song2 as? Song else {
return ComparisonResult.orderedSame
}
if s1.position < s2.position {
return ComparisonResult.orderedAscending
} else if s1.position == s2.position {
return ComparisonResult.orderedSame
} else {
return ComparisonResult.orderedDescending
}
}
return array as! [Song]
} else {
return []
}
}
public var wrappedName: String {
self.name ?? "Unknown Playlist Name"
}
Как видите, я сортирую песни по их атрибуту позиции, прежде чем возвращать их в массив для последующего просмотра и повторного заказа с помощью swiftUI.
Класс песни:
extension Song {
@nonobjc public class func fetchRequest() -> NSFetchRequest<Song> {
return NSFetchRequest<Song>(entityName: "Song")
}
@NSManaged public var name: String?
@NSManaged public var position: Int16
@NSManaged public var playlist: Playlist?
public var wrappedName: String {
self.name ?? "Unknown Playlist Name"
}
}
ContentView.swift:
struct ContentView: View {
@Environment(\.managedObjectContext) var moc
@FetchRequest(entity: Playlist.entity(), sortDescriptors: []) var playlists: FetchedResults<Playlist>
var body: some View {
NavigationView {
List {ForEach(playlists, id:\.self)
{ playlist in
NavigationLink(destination:
PlaylistView(songs: playlist.songsArray) ){
Text(playlist.wrappedName)
}
}
.onDelete(perform: deletePlaylist)
}
.navigationBarTitle("Playlists")
.navigationBarItems(trailing:
Button(action: {
let newPlaylist = Playlist(context: self.moc)
newPlaylist.name = "Playlist Name"
let newSong1 = Song(context: self.moc)
newSong1.name = "Song_1"
newSong1.position = 0
newPlaylist.addToSongs(newSong1)
let newSong2 = Song(context: self.moc)
newSong2.name = "Song_2"
newSong2.position = 1
newPlaylist.addToSongs(newSong2)
newPlaylist.numberOfSongs = 2
try? self.moc.save()
}) {
Image(systemName: "plus").imageScale(.large)
})
}
}
func deletePlaylist(offsets: IndexSet) {
for index in offsets {
let playlist = playlists[index]
moc.delete(playlist)
}
do {
try moc.save()
} catch {
print(error)
}
}
}
PlaylistView:
struct PlaylistView: View {
@State var songs: [Song]
@Environment(\.managedObjectContext) var moc
var body: some View {
List { ForEach(self.songs, id: \.self)
{ song in
Text(song.wrappedName)
}
.onMove(perform: move)
}
.navigationBarTitle(Text(self.songs[0].playlist!.wrappedName))
.navigationBarItems(trailing:
Button(action: {
}) {
EditButton()
})
}
func move(from source: IndexSet, to destination: Int) {
self.songs.move(fromOffsets: source, toOffset: destination)
var counter: Int16 = 0
for song in self.songs {
song.position = counter
counter += 1
}
try! self.moc.save()
}
}
Теперь в PlaylistView, когда я переупорядочиваю массив песен, я обновляю атрибуты позиции песен до отражать новый порядок (в move ()), но теперь, когда я возвращаюсь из PlaylistView обратно в ContentView, а затем go обратно в PlaylistView, песни находятся не в новом порядке. Однако, если я перезапущу приложение и введу go в список воспроизведения, песни будут расположены в правильном новом порядке.
Насколько я понимаю, каждый раз, когда я нажимаю на NavigationLink для PlaylistView, playlist.songsArray должен захватывать массив из атрибута класса Playlist, в котором я выполняю сортировку, поэтому я не понимаю, почему песни в PlaylistView арены не отсортировано.
Любая помощь будет принята с благодарностью!
Посмотрите проект xcode здесь