Apakah benar untuk mengharapkan pembaruan internal pembungkus properti SwiftUI DynamicProperty untuk memicu pembaruan tampilan?

10

Saya mencoba membuat pembungkus properti khusus yang didukung oleh SwiftUI, yang berarti bahwa perubahan nilai properti terkait akan menyebabkan pembaruan ke tampilan SwiftUI. Ini adalah versi sederhana dari apa yang saya miliki:

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

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

Saya melihat bahwa meskipun konten saya ObservedObjectada di dalam pembungkus properti khusus saya, SwiftUI masih menerima perubahan SomeObservedObjectselama:

  • Wrapper properti saya adalah sebuah struct
  • Pembungkus properti saya sesuai dengan DynamicProperty

Sayangnya dokumennya jarang dan saya kesulitan mengatakan apakah ini hanya kurang berhasil dengan implementasi SwiftUI saat ini.

Dokumen dari DynamicProperty(dalam Xcode, bukan online) tampaknya menunjukkan bahwa properti seperti itu adalah properti yang diubah dari luar yang menyebabkan pandangan untuk digambar ulang, tetapi tidak ada jaminan tentang apa yang terjadi ketika Anda menyesuaikan jenis Anda sendiri dengan protokol ini.

Bisakah saya berharap ini terus bekerja dalam rilis SwiftUI di masa depan?

Trevör
sumber
4
Tidak jelas apa harapan dari topik ini ... jawaban pada satu pertanyaan terakhir? Apakah Anda benar-benar percaya jika seseorang menjawab "ya, tentu, Anda bisa mengharapkan"? ))
Asperi

Jawaban:

6

Ok ... di sini adalah pendekatan alternatif untuk mendapatkan hal serupa ... tetapi sebagai struct hanya DynamicPropertymelilit @State(untuk memaksa tampilan refresh).

Ini adalah pembungkus sederhana tetapi memberikan kemungkinan untuk melakukan inkapsulasi setiap kalkulasi khusus dengan penyegaran tampilan berikut ... dan sebagaimana dikatakan menggunakan tipe hanya nilai.

Ini demo (diuji dengan Xcode 11.2 / iOS 13.2):

DynamicProperty sebagai pembungkus di @State

Ini kode:

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
sumber