Est-il correct de s'attendre à ce que des mises à jour internes d'un wrapper de propriété SwiftUI DynamicProperty déclenchent une mise à jour de la vue?

10

J'essaie de créer un wrapper de propriété personnalisé pris en charge par SwiftUI, ce qui signifie que les modifications apportées aux valeurs de propriétés correspondantes entraîneraient une mise à jour de la vue SwiftUI. Voici une version simplifiée de ce que j'ai:

@propertyWrapper
public struct Foo: DynamicProperty {
    @ObservedObject var observed: SomeObservedObject

    public var wrappedValue: [SomeValue] {
        return observed.value
    }
}

Je vois que même si mon ObservedObjectest contenu à l'intérieur de mon wrapper de propriété personnalisée, SwiftUI intercepte toujours les modifications SomeObservedObjecttant que:

  • Mon wrapper de propriété est une structure
  • Mon wrapper de propriété est conforme à DynamicProperty

Malheureusement, les documents sont rares et j'ai du mal à dire si cela ne fonctionne que par chance avec la mise en œuvre actuelle de SwiftUI.

Les documents de DynamicProperty(dans Xcode, pas en ligne) semblent indiquer qu'une telle propriété est une propriété qui est modifiée de l'extérieur, ce qui entraîne la redessine de la vue, mais il n'y a aucune garantie de ce qui se passe lorsque vous conformez vos propres types à ce protocole.

Puis-je m'attendre à ce que cela continue de fonctionner dans les futures versions de SwiftUI?

Trevör
la source
4
On ne sait pas à quoi s'attendre de ce sujet ... réponse à une dernière question? Croirez-vous vraiment si quelqu'un répond "oui, bien sûr, vous pouvez vous attendre"? ))
Asperi

Réponses:

6

Ok ... voici une approche alternative pour obtenir DynamicPropertyquelque chose de similaire ... mais en tant que struct uniquement enroulé @State(pour forcer le rafraîchissement de la vue).

Il s'agit d'un simple wrapper mais donne la possibilité d'incapsuler tous les calculs personnalisés avec l'actualisation de la vue suivante ... et comme indiqué en utilisant des types de valeur uniquement.

Voici la démo (testée avec Xcode 11.2 / iOS 13.2):

DynamicProperty en tant que wrapper sur @State

Voici le code:

import SwiftUI

@propertyWrapper
struct Refreshing<Value> : DynamicProperty {
    let storage: State<Value>

    init(wrappedValue value: Value) {
        self.storage = State<Value>(initialValue: value)
    }

    public var wrappedValue: Value {
        get { storage.wrappedValue }

        nonmutating set { self.process(newValue) }
    }

    public var projectedValue: Binding<Value> {
        storage.projectedValue
    }

    private func process(_ value: Value) {
        // do some something here or in background queue
        DispatchQueue.main.async {
            self.storage.wrappedValue = value
        }
    }

}


struct TestPropertyWrapper: View {

    @Refreshing var counter: Int = 1
    var body: some View {
        VStack {
            Text("Value: \(counter)")
            Divider()
            Button("Increase") {
                self.counter += 1
            }
        }
    }
}

struct TestPropertyWrapper_Previews: PreviewProvider {
    static var previews: some View {
        TestPropertyWrapper()
    }
}
Asperi
la source