¿Es correcto esperar actualizaciones internas de un contenedor de propiedades SwiftUI DynamicProperty para activar una actualización de vista?

10

Estoy tratando de crear un contenedor de propiedades personalizado compatible con SwiftUI, lo que significa que los cambios en los valores de propiedades correspondientes causarían una actualización de la vista SwiftUI. Aquí hay una versión simplificada de lo que tengo:

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

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

Veo que incluso si mi ObservedObjectestá contenido dentro de mi contenedor de propiedades personalizadas, SwiftUI aún captura los cambios SomeObservedObjectsiempre que:

  • Mi contenedor de propiedades es una estructura
  • Mi envoltorio de propiedad se ajusta a DynamicProperty

Desafortunadamente, los documentos son escasos y me cuesta mucho saber si esto solo funciona por suerte con la implementación actual de SwiftUI.

Los documentos de DynamicProperty(dentro de Xcode, no en línea) parecen indicar que dicha propiedad es una propiedad que se cambia desde el exterior, lo que hace que la vista se vuelva a dibujar, pero no hay garantía sobre lo que sucede cuando se ajustan sus propios tipos a este protocolo.

¿Puedo esperar que esto continúe funcionando en futuros lanzamientos de SwiftUI?

Trevör
fuente
44
No está claro cuál es la expectativa de este tema ... ¿responder a la última pregunta? ¿Realmente creerás si alguien responde "sí, claro, puedes esperar"? ))
Asperi

Respuestas:

6

Ok ... aquí hay un enfoque alternativo para obtener algo similar ... pero como estructura solo se DynamicPropertyenvuelve @State(para forzar la actualización de la vista).

Es un contenedor simple, pero ofrece la posibilidad de encapsular cualquier cálculo personalizado con la siguiente actualización de vista ... y, como se dijo, utilizando tipos de solo valor.

Aquí está la demostración (probada con Xcode 11.2 / iOS 13.2):

DynamicProperty como contenedor en @State

Aquí está el código:

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
fuente