È corretto aspettarsi che gli aggiornamenti interni di un wrapper di proprietà SwiftUI DynamicProperty attivino un aggiornamento della vista?


10

Sto tentando di creare un wrapper di proprietà personalizzato supportato da SwiftUI, il che significa che le modifiche ai valori delle proprietà corrispondenti causerebbero un aggiornamento della vista SwiftUI. Ecco una versione semplificata di ciò che ho:

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

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

Vedo che anche se my ObservedObjectè contenuto all'interno del mio wrapper di proprietà personalizzato, SwiftUI continua a rilevare le modifiche fino SomeObservedObjecta quando:

  • Il mio wrapper di proprietà è una struttura
  • Il mio wrapper di proprietà è conforme a DynamicProperty

Sfortunatamente i documenti sono scarsi e ho difficoltà a dire se questo funziona solo sfortunatamente con l'attuale implementazione di SwiftUI.

I documenti di DynamicProperty(all'interno di Xcode, non online) sembrano indicare che tale proprietà è una proprietà che viene modificata dall'esterno causando il ridisegno della vista, ma non vi è alcuna garanzia su ciò che accade quando si conformano i propri tipi a questo protocollo.

Posso aspettarmi che questo continui a funzionare nelle versioni future di SwiftUI?


4
Non è chiaro quale sia l'aspettativa di questo argomento ... risposta sull'ultima domanda? Ci crederai davvero se qualcuno rispondesse "sì, certo, puoi aspettarti"? ))
Asperi

Risposte:


6

Ok ... ecco un approccio alternativo per ottenere qualcosa di simile ... ma come struct DynamicPropertyavvolto solo @State(per forzare l'aggiornamento della vista).

È un semplice wrapper ma offre la possibilità di incapsulare tutti i calcoli personalizzati con il seguente aggiornamento della vista ... e, come detto, utilizzando tipi di solo valore.

Ecco la demo (testata con Xcode 11.2 / iOS 13.2):

DynamicProperty come wrapper su @State

Ecco il codice:

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()
    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.