SwiftUI中的MVVM模型

jdg4fx2g  于 2023-01-29  发布在  Swift
关注(0)|答案(2)|浏览(217)

我想根据MVVM从视图模型中分离视图。我如何在SwiftUI中创建模型?我读到应该使用结构而不是类。
作为一个例子,我有一个公园的模型,你可以种树:

// View Model
struct Park {
  var numberOfTrees = 0
  func plantTree() {
    numberOfTrees += 1 // Cannot assign to property: 'self' is immutable
  }
}

// View
struct ParkView: View {
  var park: Park
  var body: some View {
    // …
  }
}

在这样的东西中阅读关于@State的东西,这使得结构体有些可变,所以我尝试:

struct Park {
  @State var numberOfTrees = 0 // Enum 'State' cannot be used as an attribute
  func plantTree() {
    numberOfTrees += 1 // Cannot assign to property: 'self' is immutable
  }
}

我确实在View中成功地直接使用了@State,但这对分离视图模型代码没有帮助。
我可以使用class

class Park: ObservableObject {
  var numberOfTrees = 0
  func plantTree() {
    numberOfTrees += 1
  }
}

...但是我在使用嵌套在另一个视图模型中的视图模型时会遇到麻烦,比如City

struct City {
  @ObservedObject var centerPark: Park
}

centerPark中的更改不会发布为Park现在是引用类型(至少在我的测试或here中不会)。另外,我想知道您如何使用struct解决此问题。

klr1opcd

klr1opcd1#

作为一个起点:

// Model
struct Park {
    var numberOfTrees = 0
    mutating func plantTree() {  // `mutating`gets rid of your error
        numberOfTrees += 1
    }
}

// View Model
class CityVM: ObservableObject {
    
    @Published var park = Park() // creates a Park and publishes it to the views
    
    // ... other @Published things ...
    
    // Intents:
    func plantTree() {
        park.plantTree()
    }
}

// View
struct ParkView: View {
    
    // create the ViewModel, which creates the model(s)
    // usually you would do this in the App struct and make available to all views by .environmentObject
    @StateObject var city = CityVM()
    
    var body: some View {
        VStack {
            Text("My city has \(city.park.numberOfTrees) trees.")
            
            Button("Plant one more") {
                city.plantTree()
            }
        }
    }
}
umuewwlo

umuewwlo2#

mutating func是修复,但我想我会包括一些其他信息如下:
我们不将MVVM与SwiftUI一起使用,因为我们不将类用于 transient 视图状态,并且我们不从MVVM/MVC的Angular 控制视图。SwiftUI自动为我们创建和更新真实的视图对象,即UILabels、UITableView等。SwiftUI View结构本质上已经是视图模型,因此,如果您要将其重新创建为对象,不仅会不必要地使代码更加复杂,而且还会引入对象引用错误,SwiftUI正试图通过使用结构来消除这些错误。使用@State@Binding这样的属性 Package 器,SwiftUI正在发挥一些魔力,使结构体的行为像一个对象,忽略这一点并不是一个好主意。要使视图结构体更具可测试性,可以将相关的变量提取到结构体中,并使用如下所示的变异函数:

// View Model
struct ParkConfig {
  var numberOfTrees = 0
  mutating func plantTree() {
    numberOfTrees += 1
  }
}

struct ContentView {
    @State var parkConfig = ParkConfig()

    var body: some View {
        ParkView(config: $parkConfig)
    }
}

// View
struct ParkView: View {
  @Binding var config: ParkConfig
  var body: some View {
      Button("Click Me") {
          config.plantTree()
      }
  }
}

你可以看到苹果在4:18的Data Essentials in SwiftUI WWDC 2020中演示了这种模式,他说:“EditorConfig可以维护其属性的不变量,并且可以独立测试。由于EditorConfig是一种值类型,因此对EditorConfig属性的任何更改(如其进度)都可以作为对EditorConfig本身的更改看到。”

相关问题