如何在更改时将代码块与@State var 关联

How to associate a block of code with a @State var when it changes

每当 @State 变量 myData 的值发生变化时,我希望收到通知并将该数据存储在 @AppStorage 变量 myStoredData 中。但是,我不想在状态变量发生更改的任何地方都显式地编写此存储代码,我想将一段代码与其相关联,以便在状态变量发生更改并执行存储时得到通知。这样做的原因是,例如,我想将状态变量作为绑定传递给另一个视图,当该视图更改变量时,存储块将自动执行。我该怎么做 this/can 我在 SwiftUI 中做到这一点?

struct MyView : View {
  @AppStorage("my-data") var myStoredData : Data!
  @State var myData : [String] = ["hello","world"]
  var body : some View {
    Button(action: {
      myData = ["something","else"]
      myStoredData = try? JSONEncoder().encode(myData)
    }) {
      Text("Store data when button pressed")
    }
    .onAppear {
        myData = (try? JSONDecoder().decode([String].self, from: myStoredData)) ?? []
    }
  }
}

我正在寻找这样的东西,但这不起作用:

@State var myData : [String] = ["hello","world"] {
  didSet {
    myStoredData = try? JSONEncoder().encode(myData)
  }
}

您可以在绑定中添加一个设置回调扩展来监控值的变化

extension Binding {

    /// When the `Binding`'s `wrappedValue` changes, the given closure is executed.
    /// - Parameter closure: Chunk of code to execute whenever the value changes.
    /// - Returns: New `Binding`.
    func onChange(_ closure: @escaping () -> Void) -> Binding<Value> {
        Binding(get: {
            wrappedValue
        }, set: { newValue in
            wrappedValue = newValue
            closure()
        })
    }
}

使用扩展代码

$myData.onChange({

})

只需在视图中的任何位置使用 .onChange 修饰符(就像您对 .onAppear 所做的那样)

struct MyView : View {
  @AppStorage("my-data") var myStoredData : Data!
  @State var myData : [String] = ["hello","world"]

  var body : some View {
    Button(action: {
      myData = ["something","else"]
      myStoredData = try? JSONEncoder().encode(myData)
    }) {
      Text("Store data when button pressed")
    }
    .onChange(of: myData) {
        myStoredData = try? JSONEncoder().encode([=10=])      // << here !!
    }
    .onAppear {
        myData = (try? JSONDecoder().decode([String].self, from: myStoredData)) ?? []
    }
  }
}