É correto esperar atualizações internas de um wrapper de propriedade SwiftUI DynamicProperty para acionar uma atualização de exibição?

10

Estou tentando criar um wrapper de propriedade personalizado suportado pelo SwiftUI, o que significa que alterações nos valores das propriedades correspondentes causariam uma atualização na exibição do SwiftUI. Aqui está uma versão simplificada do que eu tenho:

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

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

Vejo que, mesmo que meu ObservedObjectesteja contido dentro do meu wrapper de propriedade personalizado, o SwiftUI ainda captura as alterações SomeObservedObjectdesde que:

  • Meu invólucro de propriedade é uma estrutura
  • Meu invólucro de propriedade está em conformidade com DynamicProperty

Infelizmente, os documentos são escassos e tenho dificuldade em dizer se isso só funciona com a implementação atual do SwiftUI.

Os documentos de DynamicProperty(no Xcode, não on-line) parecem indicar que essa propriedade é alterada externamente, fazendo com que a exibição seja redesenhada, mas não há garantia sobre o que acontece quando você conforma seus próprios tipos a este protocolo.

Posso esperar que isso continue funcionando em versões futuras do SwiftUI?

Trevör
fonte
4
Não está claro qual é a expectativa deste tópico ... responder sobre a última pergunta? Você realmente acreditará se alguém responder "sim, claro, você pode esperar"? ))
Asperi 06/01

Respostas:

6

Ok ... aqui está uma abordagem alternativa para obter uma coisa semelhante ... mas como struct apenas DynamicPropertyenvolvida @State(para forçar a atualização da visualização).

É um invólucro simples, mas oferece a possibilidade de incluir todos os cálculos personalizados com a seguinte atualização de exibição ... e, como dito, usando tipos somente de valor.

Aqui está a demonstração (testada com o Xcode 11.2 / iOS 13.2):

DynamicProperty como wrapper no @State

Aqui está o 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
fonte