Ist es richtig zu erwarten, dass interne Aktualisierungen eines SwiftUI DynamicProperty-Eigenschafts-Wrappers eine Ansichtsaktualisierung auslösen?

10

Ich versuche, einen benutzerdefinierten Eigenschaften-Wrapper zu erstellen, der von SwiftUI unterstützt wird. Dies bedeutet, dass Änderungen an den entsprechenden Eigenschaftenwerten eine Aktualisierung der SwiftUI-Ansicht bewirken würden. Hier ist eine vereinfachte Version von dem, was ich habe:

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

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

Ich sehe, dass ObservedObjectSwiftUI die Änderungen auch dann abfängt , wenn meine in meinem benutzerdefinierten Eigenschafts-Wrapper enthalten ist, SomeObservedObjectsolange:

  • Mein Property Wrapper ist eine Struktur
  • Mein Property Wrapper entspricht DynamicProperty

Leider sind die Dokumente spärlich und es fällt mir schwer zu sagen, ob dies nur mit der aktuellen SwiftUI-Implementierung aus Glück funktioniert.

Die Dokumente von DynamicProperty(innerhalb von Xcode, nicht online) scheinen darauf hinzuweisen, dass eine solche Eigenschaft eine Eigenschaft ist, die von außen geändert wird, wodurch die Ansicht neu gezeichnet wird. Es gibt jedoch keine Garantie dafür, was passiert, wenn Sie Ihre eigenen Typen an dieses Protokoll anpassen.

Kann ich davon ausgehen, dass dies auch in zukünftigen SwiftUI-Versionen funktioniert?

Trevör
quelle
4
Es ist nicht klar, was die Erwartung an dieses Thema ist ... Antwort auf die letzte Frage? Glauben Sie wirklich, wenn jemand mit "Ja, sicher, Sie können es erwarten" antwortet? ))
Asperi

Antworten:

6

Ok ... hier ist ein alternativer Ansatz, um ähnliche Dinge zu erhalten ... aber als Struktur nur DynamicPropertyumwickelt @State(um die Aktualisierung der Ansicht zu erzwingen).

Es ist ein einfacher Wrapper, bietet jedoch die Möglichkeit, benutzerdefinierte Berechnungen mit der folgenden Ansichtsaktualisierung zu kapseln ... und wie gesagt nur mit Werttypen.

Hier ist eine Demo (getestet mit Xcode 11.2 / iOS 13.2):

DynamicProperty als Wrapper in @State

Hier ist 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
quelle