Swift data issue in queries in iOS 18, no pb in iOS 17

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 !

Answered by boujouman in 808310022

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 []
    }
}
Accepted Answer

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 []
    }
}
Swift data issue in queries in iOS 18, no pb in iOS 17
 
 
Q