【问题标题】:How to update a complicated model of a View from within its body如何从其主体内更新视图的复杂模型
【发布时间】:2020-01-04 20:58:47
【问题描述】:

我正在构建一个带有大型复杂模型的自定义 View 结构,我想从 var body : some View { ... } 属性中更新它(例如,点击代表视图中表列的按钮应该会更改行的排序顺序表中)。我不能在body 中修改这个模型,因为self 是不可变的:

struct MyTable : View {

  struct Configuration {
     // a LOT of data here, ie header, rows, footer, style, etc

     mutating func update() { ... } // this method must be called before view render
  }
  var configuration : Configuration

  var body : some View {
    // build the view here based on configuration
    self.configuration.columns[3].sortAscending = false // error, `self` is immutable
    self.configuration.update() // error, `self` is immutable
  }
}

我真的不想为所有配置数据创建@State 变量,因为 1) 有很多配置数据,2) 很难以这种方式对模型进行建模。

我尝试将configuration 设置为@State var,但即使代码编译并运行,我也无法在init() 时间设置配置对象! (顺便说一句,configuration var 现在需要在 init 之前进行初始化,否则我会在 self.configuration = c 行出现错误,即在所有成员初始化之前使用 self - 这可能是使用 @State 的复杂情况是一个属性包装器。)

struct MyTable : View {

  struct Configuration {
     ...
  }

  @State var configuration : Configuration = Configuration() // must initialize the @State var

  init(configuration c: Configuration) {
    self.configuration = c // does not assign `c` to `configuration` !!!
    self.$configuration.wrappedValue = c // this also does not assign !!!
    self.configuration.update()
  }

  var body : some View {
    // build the view here based on configuration
    self.configuration.columns[3].sortAscending = false // ok, no error now about mutating a @State var
    self.configuration.update() // ok, no error
  }
}

【问题讨论】:

  • 只有视图相关的变量需要在body内更新。
  • 视图是根据配置(即模型)构建的。
  • @State 的误用。对于您描述的用例,您需要基于 ObservableObject 的 ViewModel 模式。
  • 我尝试在初始化时将模型注入到视图中。

标签: state swiftui


【解决方案1】:

我想出了一个解决方法,我不需要在 MyTable.init() 中调用 update(),方法是在 Configuration 中创建一个自定义 init(),它将调用 update()。这样MyTable 中的init() 就不需要了,而且这种方法解决了之前遇到的所有问题:

struct MyTable : View {

  struct Configuration {
     ...

     init(...) {
         ...
         self.update()
     }

     mutating func update() { ... } // this method must be called before view render
  }

  @State var configuration : Configuration // note that this property can't be marked private because we want to inject `configuration` at init

  var body : some View {
    // build the view here based on configuration
    self.configuration.columns[3].sortAscending = false // ok, no error now about mutating a @State var
    self.configuration.update() // ok, no error
    ...
  }
}

然后在我的调用代码中:

return MyTable.init(configuration: MyTable.Configuration.init(...))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-11-06
    • 2013-10-31
    • 2018-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多