Problèmes de passage de paramètre

Je veux mettre de l’ordre dans mon code et mettre la fonction loadData dans son propre fichier
si je passe [Result] en paramètre de loadData j’ai un message qui me dit que je ne peux pas modifier une constante

struct Response: Codable {
var results: [Result]
}

struct ContentView: View {
@State var results = Result
@State var enteredText: String = «  »

var body: some View {
    NavigationView {
        VStack {
            TextField("Recherche: ", text: $enteredText, onCommit:  {
                let replaced = enteredText.replacingOccurrences(of: " ", with: "+")
                loadData(artist: replaced)
            })
            .modifier(ClearButton(editedText: $enteredText))
            .textFieldStyle(RoundedBorderTextFieldStyle())
            .padding()

}

func loadData(artist: String) {
guard let url = URL(string: « https://itunes.apple.com/search?term=(artist)&entity=song ») else { print(« Invalid URL »); return
}

    let request = URLRequest(url: url)
    
    URLSession.shared.dataTask(with: request) { (data, response, error) in
        if let data = data {
            if let decodedResponse = try? JSONDecoder().decode(Response.self, from: data) {
                DispatchQueue.main.async {
                    self.results = decodedResponse.results
                }
                return
            }
        }
        
        print("Fetch failed: \(error?.localizedDescription ?? "Unknown error")")
    }.resume()
}

Utilise une classe à la place d’une struct, pour l’objet gérant le modèle de données.

Je ne vois pas tellement comment procéder
merci pour ton aide

le projet est sur GitHub

Bonjour,

Comment j’ai procédé pour passer des valeurs ou appel de fonction sous SwiftUI.

class Management {
  @Published var value1:Int

   func loadData () {
    print("je suis dans la fonction loadData")
  }
}

dans ta vue principale où tu à ton NavigationView il faut appeler ta class avec         '.environmentObject(appManagement)'
struct MainView: View {
    let management = Management()
    var body: some View {
        NavigationView {
            enfant1View()
        }
        .environmentObject(management)
    }
}

et dans toutes tes vues enfants tu peux y accéder en
@EnvironmentObject var appManagement : AppManagement
comme tu accède aussi à toute tes variables environnement avec le @Published déclarer dans ta class

struct enfant1View: View {
    @EnvironmentObject var management : Management
    
    var body: some View {
        HStack {
           Text("Ma première valeur \(value1)")
           .onTapGesture (perform: {
                  management.loadData(). })
  }
}

Dans un des cours de Maxime il explique comment dans une struct, elle peut accepter la modification d’une valeur.

On peut y arriver en ajoutant une fonction dans la struct, avec comme attribut mutable (pour indiquer qu’elle a le droit de modifier le contenu).

Ouep voilà. Mutating func

Plutôt que de transmettre le tableau à la fonction, essaye une fonction retournant un tableau.

func loadData() -> [Result] {

}

Ou plutôt un tableau [Result]? s’il y a un risque d’erreur dans le chargement (ce qui est toujours le cas quand on lit une donnée depuis internet).

EDIT : Un peu complexe ton problème, en raison du chargement asynchrone des données.

Problème résolu, en tenant compte des spécificités d’un chargement asynchrone des données.

J’ai créé une classe LoadData observable pour s’occuper du chargement. Elle possède une fonction loadData() et un tableau results avec l’attribut @Published.

import Foundation

class LoadData: ObservableObject {
  @Published var results = [Result]()
  
  func loadData(artist: String) {
    
    guard let url = URL(string: "https://itunes.apple.com/search?term=\(artist)&entity=song")
    else { print("Invalid URL"); return
    }
    
    let request = URLRequest(url: url)
    
    URLSession.shared.dataTask(with: request) { (data, response, error) in
      if let data = data {
        if let decodedResponse = try? JSONDecoder().decode(Response.self, from: data) {
          DispatchQueue.main.async {
            self.results = decodedResponse.results
          }
          return
        }
      }
      
      print("Fetch failed: \(error?.localizedDescription ?? "Unknown error")")
    }.resume()
    
  }
  
}

Cela s’utilise comme ça :

struct ContentView: View {
  @ObservedObject var loadData = LoadData()
  @State var enteredText: String = ""
    
    var body: some View {
        NavigationView {
            VStack {
                TextField("Recherche: ", text: $enteredText, onCommit:  {
                    let replaced = enteredText.replacingOccurrences(of: " ", with: "+")
                  loadData.loadData(artist: replaced)
                })
                .modifier(ClearButton(editedText: $enteredText))
                .textFieldStyle(RoundedBorderTextFieldStyle())
                .padding()
                
              if loadData.results.count != 0 {
                List(loadData.results, id: \.trackId) { item in
                        
                        VStack(alignment: .leading) {
                            
                            UrlImageView(urlString: item.artworkUrl30)
                                .frame(width: 30, height: 30)
                            
                            Text(item.trackName)
                                .font(.headline)
                            
                            Text(item.collectionName)
                            
                            Text(item.artistName)
                                .foregroundColor(.red)
                        }
                        
                        
                        NavigationLink("", destination: PlayerView(item: item))
                           
                        
                    }
                } else {
                    
                    Image(systemName: "music.note")
                        .resizable()
                        .frame(width: UIScreen.main.bounds.size.width - 20, height: UIScreen.main.bounds.size.height - 200, alignment: .center)
                    
                    
                }
            }
            .navigationBarTitle("Apple Music")
            .navigationBarTitleDisplayMode(.inline)
            .background(Color.blue)
        }
    }
}

Tous les paramètres de lecture sont stockés dans la classe LoadData, et accessibles via sa propriété results. Etant donné que c'est une @Published, la View est automatiquement prévenue en cas de changement (quand les données asynchrones sont toutes chargées en mémoire).

Merci à vous deux, c’est très sympa d’aider des gens comme moi empêtrés dans des problèmes de base.
Merci grâce à vous, je commence à comprendre mieux les choses.
Quand tout le code est dans la même vue, les problèmes ne se posent pas.
Les problèmes commencent quand on veut nettoyer le code, c’est ce qu’a bien expliqué Maxime dans créer des apps avec iOS14.
j’ai d’ailleurs refait le passage ou on nettoie le code.
Naturellement en suivant vos conseils çà fonctionne !