17

SwiftUI でサポートされているカスタム プロパティ ラッパーを作成しようとしています。つまり、対応するプロパティ値を変更すると、SwiftUI ビューが更新されます。ここに私が持っているものの簡略版があります:

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

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

my がカスタム プロパティ ラッパー内に含まれている場合でもObservedObject、SwiftUI は次のSomeObservedObject限り変更をキャッチします。

  • 私のプロパティラッパーは構造体です
  • 私のプロパティラッパーは以下に準拠していますDynamicProperty

残念ながら、ドキュメントはまばらであり、これが現在の SwiftUI 実装でのみ機能するかどうかを判断するのは困難です。

ドキュメントDynamicProperty(オンラインではなく Xcode 内) は、そのようなプロパティが外部から変更されてビューが再描画されるプロパティであることを示しているようですが、独自の型をこのプロトコルに準拠させたときに何が起こるかについての保証はありません。

これは今後の SwiftUI リリースでも機能し続けると期待できますか?

4

4 に答える 4

15

わかりました...これは同様のものを取得するための代替アプローチです...ただし、構造体はDynamicPropertyラップアラウンドのみです@State(ビューの更新を強制するため)。

これは単純なラッパーですが、次のビューの更新でカスタム計算をカプセル化する可​​能性を提供します...そして前述のように値のみの型を使用します。

これがデモです(Xcode 11.2 / iOS 13.2でテスト済み):

@State のラッパーとしての DynamicProperty

コードは次のとおりです。

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()
    }
}
于 2020-01-07T05:56:08.860 に答える
1

タイトルの質問については、いいえ。たとえば、次のコードは機能しません。

class Storage {
    var value = 0
}

@propertyWrapper
struct MyState: DynamicProperty {
    var storage = Storage()

    var wrappedValue: Int {
        get { storage.value }

        nonmutating set {
            storage.value = newValue // This doesn't work
        }
    }
}

どうやら、Asperi のように更新をトリガーするには、StateまたはObservedObjectなどを内部に配置する必要があるようです。a自体は更新を強制しません。DynamicPropertyDynamicProperty

于 2021-01-27T02:20:24.993 に答える