ถูกต้องหรือไม่หากคาดว่าการอัปเดตภายในของเครื่องห่อคุณสมบัติ SwiftUI DynamicProperty เพื่อเรียกการอัปเดตมุมมอง


10

ฉันกำลังพยายามสร้าง wrapper คุณสมบัติที่กำหนดเองที่สนับสนุนโดย SwiftUI ซึ่งหมายความว่าการเปลี่ยนแปลงค่าคุณสมบัติที่สอดคล้องกันจะทำให้การอัปเดตเป็นมุมมอง SwiftUI นี่คือเวอร์ชั่นที่เรียบง่ายของสิ่งที่ฉันมี:

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

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

ฉันเห็นว่าแม้ว่าฉันObservedObjectจะอยู่ภายในเสื้อคลุมคุณสมบัติที่กำหนดเองของฉัน SwiftUI ยังคงจับการเปลี่ยนแปลงSomeObservedObjectตราบใดที่:

  • เสื้อคลุมทรัพย์สินของฉันเป็น struct
  • เครื่องห่อคุณสมบัติของฉันเป็นไปตาม DynamicProperty

โชคไม่ดีที่เอกสารเหล่านั้นกระจัดกระจายและฉันมีเวลาบอกได้ยากว่ามันจะโชคดีแค่ไหนกับการใช้งาน SwiftUI ในปัจจุบัน

DynamicPropertyดูเหมือนว่าเอกสารของ(ภายใน Xcode ไม่ใช่ออนไลน์) แสดงว่าคุณสมบัติดังกล่าวเป็นคุณสมบัติที่มีการเปลี่ยนแปลงจากภายนอกทำให้มุมมองการวาดใหม่ แต่ไม่มีการรับประกันเกี่ยวกับสิ่งที่เกิดขึ้นเมื่อคุณปฏิบัติตามประเภทของคุณกับโปรโตคอลนี้

ฉันคาดหวังได้ไหมว่าสิ่งนี้จะทำงานต่อไปในอนาคตของ SwiftUI


4
ไม่ชัดเจนว่าความคาดหวังของหัวข้อนี้คืออะไร ... คำตอบสำหรับคำถามสุดท้าย คุณจะเชื่อหรือไม่ถ้ามีคนตอบว่า "ใช่แน่นอนคุณคาดหวังได้" ))
Asperi

คำตอบ:


6

ตกลง ... นี่คือวิธีอื่นในการรับสิ่งที่คล้ายกัน ... แต่เนื่องจาก struct DynamicPropertyล้อมรอบเท่านั้น@State(เพื่อบังคับให้รีเฟรชมุมมอง)

มันเป็น wrapper ง่าย ๆ แต่ให้ความเป็นไปได้ที่จะแค็ปซูลการคำนวณแบบกำหนดเองใด ๆ ด้วยการรีเฟรชมุมมองต่อไปนี้ ...

นี่คือตัวอย่าง (ทดสอบด้วย Xcode 11.2 / iOS 13.2):

DynamicProperty เป็น wrapper บน @ State

นี่คือรหัส:

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()
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.