2
votes

SwiftUI: la mise à jour d'un élément de tableau ne met pas immédiatement à jour l'interface utilisateur enfant

J'ai un tableau d'éléments (nombres) à présenter à l'utilisateur en utilisant NavigationView, List et une page feuille.

Lorsque je mets à jour un élément (nombres [index] = ...) sur une page feuille, il met à jour correctement la liste (ce que je vois quand je retourne à la liste), mais pas la page feuille elle-même immédiatement. Je vois le changement si je retourne à la liste et rouvre la même page feuille.

Je voudrais comprendre pourquoi il ne met pas immédiatement à jour l'interface utilisateur et comment y remédier. Voici le code simplifié pour reproduire ce comportement.

INFORMATIONS SUPPLÉMENTAIRES Ce code fonctionne très bien sur Xcode 12. Il échoue uniquement sur Xcode 12.1 (RC1) et Xcode 12.2 (beta3).

import SwiftUI

struct NumberHolder: Identifiable {
    let id = UUID()
    let value:Int
}

struct Playground: View {
    @State var numbers:[NumberHolder] = [
        NumberHolder(value:1),
        NumberHolder(value:2),
        NumberHolder(value:3),
        NumberHolder(value:4),
    ]
    var body: some View {
        NavigationView {
            List(numbers.indices) { index in
                let number = numbers[index]
                NavigationLink(destination: VStack {
                    Text("Number: \(number.value)")
                    Button("Increment") {
                        numbers[index] = NumberHolder(value: number.value + 1)
                    }
                } ) {
                    Text("Number: \(number.value)")
                }
            }
        }
    }
}

struct Playground_Previews: PreviewProvider {
    static var previews: some View {
        Playground()
    }
}


1 commentaires

Je reçois exactement ce problème. Fonctionne avec iOS 14.1 / Xcode 12.1 mais pas avec iOS 14.2 / Xcode 12.2 RC. Toutes les idées si c'est quelque chose qu'elles ont changé avec NavigationLinks ou quelque chose qui est cassé, les forums de développement Apple sont difficiles à utiliser / obtenir de l'aide


3 Réponses :


0
votes

Essaye celui-là. J'ai testé et ça marche.

import SwiftUI

struct NumberHolder: Identifiable {
    let id = UUID()
    let value:Int
}

struct ContentView: View {   
    @State var numbers:[NumberHolder] = [
        NumberHolder(value:1),
        NumberHolder(value:2),
        NumberHolder(value:3),
        NumberHolder(value:4),
    ]
    var body: some View {
        NavigationView {
            List(numbers.indices) { index in
                NavigationLink(destination: DetailView(numbers: $numbers, index: index)) {
                    Text("Number: \(self.numbers[index].value)")
                }
            }
        }
    }
}

struct DetailView: View {
    @Binding var numbers:[NumberHolder]
    let index: Int
    
    var body: some View {
        VStack {
            Text("Number: \(self.numbers[index].value)")
            
            Button("Increment") {
                numbers[index] = NumberHolder(value: numbers[index].value + 1)
            }
        }
    }
}


1 commentaires

Merci pour une réponse rapide. Cela résout en effet ce problème particulier, mais je ne comprends toujours pas pourquoi mon échantillon ne fonctionne pas. Dans le projet sur lequel je travaille, DetailView ne sait pas que les données proviennent d'un tableau, ce qui rend impossible l'utilisation de cette solution.



0
votes

J'ai trouvé la réponse. C'était un bug dans Xcode. Ce code (sans aucune modification) fonctionne correctement sous Xcode 12.0, mais ne parvient pas à se mettre à jour sous Xcode 12.2 beta 2.


1 commentaires

Ce bogue est également dans Xcode 12.1.1 (12A7605b).



1
votes

Cela m'a fait gratter ma journée pendant quelques semaines.

Il semble que de nombreuses fonctionnalités de SwiftUI ne fonctionnent pas dans les Views placées directement dans les Lists , mais si vous ajoutez un ForEach à l'intérieur de la List , les fonctionnalités (telles que .listRowPlatterColor(.green) sur WatchOS) commencent à fonctionner.

Solution

Sur iOS 14.2, si vous ForEach le NavigationLink dans un ForEach la destination NavigationLink (page feuille) sera mise à jour immédiatement lorsque le modèle de données est mis à jour.

Alors changez votre code en

var body: some View {
        NavigationView {
            List {
                ForEach(numbers.indices) { index in
                    let number = numbers[index]
                    NavigationLink(destination: VStack {
                        Text("Number: \(number.value)")
                        Button("Increment") {
                            numbers[index] = NumberHolder(value: number.value + 1)
                        }
                    } ) {
                        Text("Number: \(number.value)")
                    }
                }
            }
        }
    }

Frustrant, cela ne résout pas le problème lors de l'utilisation de WatchOS, dans WatchOS 7.0 la page feuille est mise à jour, cependant dans WatchOS 7.1 (la version va de pair avec iOS 14.2 qui a souffert de ce "problème") donc j'ai un problème ouvert avec Apple FB8892330

Encore plus frustrant, je ne sais toujours pas s'il s'agit d'un bogue ou d'une fonctionnalité de SwiftUI, aucune documentation ForEach l' exigence de ForEach intérieur des Lists


0 commentaires