Dear community !!!
I'm brand new in SwiftUI development. I created an app, I was almost at the end with fine tuning when I got weird behaviours with the iOS 18 version when using Swift Data.
I think I'm part of the problem but I can not figure out how to solve it. I've searched, spent so many hours and feel a bit disappointed not succeeding.
Here is my first problem :
I've two models :
@Model
class Song: Codable {
var uuid: UUID = UUID()
var text: String = ""
var creationDate: Date = Date.now
var updatingDate: Date = Date.now
var status: Int = 0
var nbRead: Int = 0
var speed: Float = 0.5
var language: String = ""
enum CodingKeys: CodingKey {
case uuid, text, creationDate, updatingDate, status, nbRead, speed, language
}
@Relationship(inverse: \Genre.songs)
var genres: [Genre]?
...
}
and
@Model
class Genre {
//var uuid: UUID
var name: String = ""
var color: String = "Red"
var songs: [Song]?
init( name: String, color: String) {
//self.uuid = uuid
self.name = name
self.color = color
}
}
I want to list all songs organised by sections :
import SwiftData
import SwiftUI
struct SongsListView: View {
private var searchingText: String
@Environment(\.modelContext) private var modelContext
@Query(sort: \Genre.name) private var genres: [Genre]
@Query var songs : [Song]
init(searchText: String)
{
if !searchText.isEmpty {
let predicate = #Predicate<Song> { song in
song.text.localizedStandardContains(searchText)
}
_songs = Query(filter: predicate)
}
searchingText = searchText
}
var body: some View {
HStack{
List{
if !songs.isEmpty {
ForEach(genres, id: \.name){ genre in
Section(header: Text(genre.name)){
ForEach (songs){song in
if let songGenres = song.genres {
if songGenres.contains(genre){
NavigationLink {
SongView(song: song)
} label: {
Text(song.text)
}
}
}
}
}
}
.onDelete { indexSet in
indexSet.forEach { index in
let song = songs[index]
modelContext.delete(song)
}
}
Section(header: Text("Without Genre")) {
ForEach (songs){song in
if let songGenres = song.genres {
if songGenres.isEmpty{
NavigationLink {
SongView(song: song)
} label: {
Text(song.text)
}
}
}
}
.onDelete { indexSet in
indexSet.forEach { index in
let song = songs[index]
modelContext.delete(song)
}
}
}
}
}
.scrollContentBackground(.hidden)
}
}
}
On iOS 17, creating a new song adds it directly to the list in the Without Genre section. On iOS 18, it takes around 30 seconds to be added.
I did a video, and I have a demo project to illustrate if necessary.
Thanks a lot for any hint, advice !
Finally, I found where the issue was :
Section(header: Text("Without Genre")) {
ForEach (songs){song in
if let songGenres = song.genres { // <-- PB is here !
if songGenres.isEmpty{
NavigationLink {
SongView(song: song)
} label: {
Text(song.text)
}
}
}
}
.onDelete { indexSet in
indexSet.forEach { index in
let song = songs[index]
modelContext.delete(song)
}
}
}
Then I decided to bypass by calling a function to get the song's genre.
Section(header: Text("Without Genre")) {
ForEach (songs){song in
let songGenres = getGenres(song) { // Change has been made
if songGenres.isEmpty{
NavigationLink {
SongView(song: song)
} label: {
Text(song.text)
}
}
}
}
.onDelete { indexSet in
indexSet.forEach { index in
let song = songs[index]
modelContext.delete(song)
}
}
}
And the func :
func getGenres(song: Song) -> [Genre] {
if let genres = song.genres {
return genres
} else {
return []
}
}