0
votes

Comment éviter d'invoquer init () dans la feuille lorsque la vue parente est mise à jour à Swiftui

TestView3 peut afficher 2 feuilles: Testview4 et TestView5. TestView4 a une valeur @state qui initialise de TestView3. Testview5 a @ObservedObject Valeur initialisée de TestView3 aussi.

Lorsque je bascule la valeur globale (global.on), il mettra à jour TestView3, puis causera TestView4 ou TestView5 init (). P>

Q1. Comment éviter d'invoquer Init () dans TestView4 ou TestView5 lorsque TestView3 mises à jour? Comment isoler totalement une vue avec une feuille de la vue? Ou toute mise à jour dans une vue affectera la feuille, c'est affreux. P>

Q2. Les comportements d'Init () dans TestView4 ou TestView5 ne sont pas les mêmes. Le local @state à TestView4 ne changera pas à init (). Mais le local @OBServedObject sera changé à init (). Pourquoi? Il est tellement bizarre. Comment faire @OBServedObject non modifié à init () en raison de la mise à jour de testview3? P>

Vous pouvez tester le code suivant, le journal de trace est si bizarre. P>

class Global: ObservableObject {
    static let shared = Global()
    @Published var on: Bool = false
}

class Local: ObservableObject {
    @Published var on: Bool = false
    init(_ on: Bool) {
        self.on = on
    }
}

struct TestView3: View {
    @ObservedObject var global = Global.shared
    @State private var sheetShowing = false
    @State private var sheetShowingId = 4
    var body: some View {
        print("test view3 body, glabel on = \(global.on)"); return
        VStack {
            Text("Global").foregroundColor(global.on ? .red : .gray).onTapGesture {
                self.global.on.toggle()
            }.padding()
            Button(action: {
                self.sheetShowing = true
                self.sheetShowingId = 4
                print("test view3, will show test view4")
            }) { Text("Show TestView4") }.padding()
            Button(action: {
                self.sheetShowing = true
                self.sheetShowingId = 5
                print("test view3, will show test view5")
            }) { Text("Show TestView5") }.padding()
        }.sheet(isPresented: $sheetShowing) {
            if self.sheetShowingId == 4 {
                TestView4(on: self.global.on)
            } else {
                TestView5(on: self.global.on)
            }
        }
    }
}

struct TestView4: View {
    @State private var on: Bool
    init(on: Bool) {
        self._on = State(initialValue: on)
        print("test view4 init, glabel on = \(Global.shared.on), local on = \(self.on)")
    }
    var body: some View {
        print("test view4 body, glabel on = \(Global.shared.on), local on = \(on)"); return
        VStack {
            Text("TestView4").padding()
            Text("Local").foregroundColor(on ? .red : .gray).onTapGesture {
                self.on.toggle()
                print("test view4, local toggle")
            }.padding()
            Text("Global").foregroundColor(Global.shared.on ? .red : .gray).onTapGesture {
                Global.shared.on.toggle()
                print("test view4, global toggle")
            }.padding()
        }
    }
}

struct TestView5: View {
    @ObservedObject var local: Local
    init(on: Bool) {
        self._local = ObservedObject(initialValue: Local(on))
        print("test view5 init, glabel on = \(Global.shared.on), local on = \(self.local.on)")
    }
    var body: some View {
        print("test view5 body, glabel on = \(Global.shared.on), local on = \(local.on)"); return
        VStack {
            Text("TestView5").padding()
            Text("Local").foregroundColor(local.on ? .red : .gray).onTapGesture {
                self.local.on.toggle()
                print("test view5, local toggle")
            }.padding()
            Text("Global").foregroundColor(Global.shared.on ? .red : .gray).onTapGesture {
                Global.shared.on.toggle()
                print("test view5, global toggle")
            }.padding()
        }
    }
}


3 commentaires

Oui, TestView3 dépend de Global, mais TestView4 (ou TestView5) n'est pas conçu pour dépendre de Global. Vous pouvez dire TestView4 (ou TestView5) ne connaît pas du tout global. Mais lorsque TestView4 (ou TestView5) en tant que feuille de TestView3, il sera affecté tout ce que vous voulez.


Changer le code comme "Testview4 (ON: FALSE)", TestView4.Init () Invoque toujours. Journal: Test View4, View Test Global Test3 Corps, Glabel On = False Test View4 Init, GLABEL ON = FAUX, LOCAL ON = FALSE


OK, NEWDMIND, vient de trouver et lisez ce que @viewbuilder est.


3 Réponses :


0
votes

Q1: vous ne pouvez pas éviter cela fort>. Pourquoi? Chaque fois que la valeur de TestView3 est enveloppée dans l'état ou observa Object modifié, il recalcule son corps. Même dans le cas où le testView3 ou TestView4 dépendra de ces valeurs, cette partie de la déclaration xxx pré>

représente une vue et son corps doit être réévalué. P>

Q2: Cela n'a pas de réponse simple, juste parce que nous ne connaissons pas trop de détails sur la mise en œuvre des autres. Au moins, je vous suggère de ne pas dépendre de votre enquête :-). Donc, il est facile de voir que vous créez nouvelle (copie locale) de votre modèle local local () fort> dans testview5.init. P>

init(on: Bool) {
    self._local = ObservedObject(initialValue: Local(on))
    print("test view5 init, glabel on = \(Global.shared.on), local on = \(self.local.on)")
}


2 commentaires

Merci pour votre réponse. Je suis clair sur Q1. Pour Q2, oui, je ne veux pas créer une nouvelle copie. Voici un cas d'utilisateur: Je choisirai des balises pour un livre, le livre a déjà un étiquette A \ b \ c dans LIGNEVIEW, puis je affiche une feuille de sélection de balises (TagSelectorView) pour ce livre, je veux TAG A \ B \ C Sélectionné dans la feuille, je peux modifier la sélection (observé object), par exemple comme une \ C \ g. Entre-temps, une valeur globale modifiée, Bodyview Body Mise à jour - TagSelectorView init () - TagSelectorView Body Mise à jour. Ainsi, la sélection (observée objecte) sera réinitialisée sous forme de \ b \ c dans TagSelectorView init (). Comment éviter cela? Toute solution?


Tout ce que vous avez à faire (et à comprendre) est de séparer la logique commerciale et / ou les données de votre UI (présentation). Oui, je sais, presque tous les tutoriels Swiftui nous montrent le contraire, mais rappelez-vous que si vous trouvez un tel "problème" comme dans votre cas, il est temps de repenser ce que tu fais et il vaut mieux revenir en arrière. Sinon, votre code sera bientôt difficile à maintenir et plein de bugs.



-1
votes

Enfin, j'ai trouvé la raison.

@OBServedObject n'est pas le même que @state. Apple fait des œuvres spéciales sur @state. @State sera conservé dans un espace spécial indépendant sur la vue.

@OBServedObject sera initialisé à chaque fois de rafraîchissement de l'UI. Il ne peut pas restaurer la valeur comme @state.

donc, en utilisant @state au lieu de @OBServedObject.


5 commentaires

Vous avez tort! "@OBServedObject" est en réalité référence à ObservéeObject, car "@state" fait référence à l'état. Le vrai est que l'état et l'observation observent sont différents, mais c'est la seule véritable information que vous avez publiée. S'il vous plaît, supprimez votre réponse ... Ne faites pas que les lecteurs soient plus confus comme avant.


Bienvenue à discuter. Ce qui est faux? Je ne peux pas le trouver dans votre commentaire. S'il vous plaît faites votre point clair. Peut-être que j'avais tort, mais vos mots ne m'aident pas, pour moi ou d'autres lecteurs.


Objet observé ainsi que l'état sont des structures, les deux conformes au protocole dynamicproperty (variable stockée qui met à jour une propriété externe d'une vue.) La vue donne des valeurs à ces propriétés avant de recharger le corps de la vue. Ce que vous avez écrit, c'est du désordre total, désolé.


Oui, qu'est-ce que vous dites est bien connu ( développeur.apple.com/documentation/swiftui/OBServedObje CT ). Pas seulement lire, s'il vous plaît essayez. Mon point est qu'ils ne sont pas totalement les mêmes. Objet observé a des effets secondaires, c'est très dangereux. S'il vous plaît utilisez-le soigneusement ou même pas l'utiliser.


De quelle partie de Doc parlez-vous? De quels effets secondaires parlez-vous? S'il vous plaît, je n'aime pas discuter avec personne, mais ne vous mélangez pas de S ... à l'aide d'observéObject est une pratique courante et suggérée, dangereuse est votre «enquête» et votre interprétation.



0
votes

Apple fournit une nouvelle solution pour cela dans iOS14: @stateObject, il est identique à la même chose que @state pour la classe que le confort observableObject.


0 commentaires