web-dev-qa-db-fra.com

OnAppear et onDisappear dans une NavigationView d'une application SwiftUI se comportent-ils comme prévu?

Je voudrais savoir si le comportement de onAppear et de Disappear dans SwiftUI (Xcode 11 beta 6 au moment où j'écris ceci) est ce qu'un développeur trouverait plus utile ou s'il s'agit simplement d'un problème plutôt que d'une fonctionnalité.

En ce moment, si nous utilisons une navigation en cascade comme vous le trouverez dans l'exemple de code que je joins (qui se compile et fonctionne correctement dans Xcode 11b6), une sortie de console d'un utilisateur naviguant dans les deux sens ne se déclencherait que sur Apparaît uniquement dans le cas d'un nouvelle charge de vue vers l'avant (ce qui signifie aller plus loin).

Dans la navigation: Root -> NestedView1 -> NestedView2 -> NestedView3, lors de l'ajout d'un assistant de débogage à chaque étape de la vue,

  .onAppear(perform: {print("onAppear level N")})
  .onDisappear(perform: {print("onDisappear level N")})

la console de débogage montrerait

onAppear root level 0
onAppear level 1
onAppear level 2
onAppear level 3

(Pas de déclenchement onDisappear)

mais en revenant Racine <- NestedView1 <- NestedView2 <- NestedView3

la console de débogage montrerait ... rien

(Pas de déclenchement onAppear ou onDisappear)

struct NestedViewLevel3: View {

    @Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>

    var body: some View {
        VStack {
            Spacer()
            Text("Level 3")
            Spacer()
            Button(action: {
                self.presentationMode.wrappedValue.dismiss()
            }) {
                Text("Back")
                    .padding(.horizontal, 15)
                    .padding(.vertical, 2)
                    .foregroundColor(Color.white)
                    .clipped(antialiased: true)
                    .background(
                        RoundedRectangle(cornerRadius: 20)
                            .foregroundColor(Color.blue)
                            .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 40, alignment: .center)
                )
            }
            Spacer()
        }
        .navigationBarBackButtonHidden(false)
        .navigationBarTitle("Level 3", displayMode: .inline)
        .onAppear(perform: {print("onAppear level 3")})
        .onDisappear(perform: {print("onDisappear level 3")})

    }
}

struct NestedViewLevel2: View {

    @Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>

    var body: some View {
        VStack {
            Spacer()
            NavigationLink(destination: NestedViewLevel3()) {
                Text("To level 3")
                    .padding(.horizontal, 15)
                    .padding(.vertical, 2)
                    .foregroundColor(Color.white)
                    .clipped(antialiased: true)
                    .background(
                        RoundedRectangle(cornerRadius: 20)
                            .foregroundColor(Color.gray)
                            .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 40, alignment: .center)
                )
                    .shadow(radius: 10)
            }
            Spacer()
            Text("Level 2")
            Spacer()
            Button(action: {
                self.presentationMode.wrappedValue.dismiss()
            }) {
                Text("Back")
                    .padding(.horizontal, 15)
                    .padding(.vertical, 2)
                    .foregroundColor(Color.white)
                    .clipped(antialiased: true)
                    .background(
                        RoundedRectangle(cornerRadius: 20)
                            .foregroundColor(Color.blue)
                            .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 40, alignment: .center)
                )
            }
            Spacer()
        }
        .navigationBarBackButtonHidden(false)
        .navigationBarTitle("Level 2", displayMode: .inline)
        .onAppear(perform: {print("onAppear level 2")})
        .onDisappear(perform: {print("onDisappear level 2")})
    }
}

struct NestedViewLevel1: View {

    @Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>

    var body: some View {
        VStack {
            Spacer()
            NavigationLink(destination: NestedViewLevel2()) {
                Text("To level 2")
                    .padding(.horizontal, 15)
                    .padding(.vertical, 2)
                    .foregroundColor(Color.white)
                    .clipped(antialiased: true)
                    .background(
                        RoundedRectangle(cornerRadius: 20)
                            .foregroundColor(Color.gray)
                            .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 40, alignment: .center)
                )
                    .shadow(radius: 10)
            }
            Spacer()
            Text("Level 1")
            Spacer()
            Button(action: {
                self.presentationMode.wrappedValue.dismiss()
            }) {
                Text("Back")
                    .padding(.horizontal, 15)
                    .padding(.vertical, 2)
                    .foregroundColor(Color.white)
                    .clipped(antialiased: true)
                    .background(
                        RoundedRectangle(cornerRadius: 20)
                            .foregroundColor(Color.blue)
                            .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 40, alignment: .center)
                )
            }
            Spacer()
        }
        .navigationBarBackButtonHidden(false)
        .navigationBarTitle("Level 1", displayMode: .inline)
        .onAppear(perform: {print("onAppear level 1")})
        .onDisappear(perform: {print("onDisappear level 1")})
    }
}

struct RootViewLevel0: View {

    var body: some View {
        NavigationView {
        VStack {
            Spacer()
            NavigationLink(destination: NestedViewLevel1()) {
            Text("To level 1")
                .padding(.horizontal, 15)
                .padding(.vertical, 2)
                .foregroundColor(Color.white)
                .clipped(antialiased: true)
                .background(
                    RoundedRectangle(cornerRadius: 20)
                    .foregroundColor(Color.gray)
                    .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 40, alignment: .center)
                )
                .shadow(radius: 10)
        }

            Spacer()

            }
    }

        .navigationBarTitle("Root level 0", displayMode: .inline)
        .navigationBarBackButtonHidden(false)
        .navigationViewStyle(StackNavigationViewStyle())
        .onAppear(perform: {print("onAppear root level 0")})
        .onDisappear(perform: {print("onDisappear root level 0")})

    }

}


struct ContentView: View {
    var body: some View {
        RootViewLevel0()
    }
}


}

Maintenant, un développeur aurait-il plutôt onAppear et onDisappear:

1) Déclenché dans le but de lancer des actions qui ne doivent être effectuées qu'une seule fois et uniquement lorsque l'utilisateur avance, comme dans le comportement observé actuel.

2) Déclenché à chaque fois que la vue apparaît, plus comme le nom de l'action semble vouloir dire, que ce soit en arrière, en avant et n'importe quel nombre de fois.

?

Je prendrais l'option 2, simple et brutale (et ce dont j'ai besoin actuellement), mais je suis un débutant assez naïf chez NavigationView, et l'option 2 peut briser beaucoup de paradigmes établis que je ne prends pas en compte.

Vos commentaires m'aideront à savoir si le cas correspondant de l'assistant de rétroaction pour SwiftUI est légitime.

9
jpelayo

C'était un bug sur la fin d'Apple.

.onAppear () fonctionne maintenant comme il est censé le faire dans iOS 13.1 et XCode 11 Beta 7.

Lorsque vous naviguez en avant et en arrière vers NavigationView, .onAppear () se déclenchera.

2
txagPman

À partir de la version bêta de XCode 11.2 (publiée le 02/10/2019), les deux méthodes (y compris .onDisappear ()) sont correctement déclenchées.

Notez que .onDisappear() n'était pas déclenché avant cette version bêta.

5
Arshia