Swift:ViewModel 应该是结构体还是类?

标签 swift mvvm struct closures

我正在尝试在我的新项目中使用 MVVM 模式。第一次,我创建了我所有的 View 模型来构造。但是,当我使用闭包实现异步业务逻辑(例如 fetchDataFromNetwork)时,闭包会捕获旧的 View 模型值,然后更新为该值。不是新的 View 模型值。

这是 playground 中的测试代码。

import Foundation
import XCPlayground

struct ViewModel {
  var data: Int = 0

  mutating func fetchData(completion:()->()) {
    XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
    NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: "http://stackoverflow.com")!) {
      result in
      self.data = 10
      print("viewModel.data in fetchResponse : \(self.data)")
      completion()
      XCPlaygroundPage.currentPage.finishExecution()
      }.resume()
  }
}

class ViewController {
  var viewModel: ViewModel = ViewModel() {
    didSet {
      print("viewModel.data in didSet : \(viewModel.data)")
    }
  }

  func changeViewModelStruct() {
    print("viewModel.data before fetch : \(viewModel.data)")

    viewModel.fetchData {
      print("viewModel.data after fetch : \(self.viewModel.data)")
    }
  }
}

var c = ViewController()
c.changeViewModelStruct()

控制台打印

viewModel.data before fetch : 0
viewModel.data in didSet : 0
viewModel.data in fetchResponse : 10
viewModel.data after fetch : 0

问题是 ViewController 中的 View 模型没有新的值 10。

如果我将 ViewModel 更改为类,则不会调用 didSet 但 ViewController 中的 View Model 具有新值 10。

最佳答案

你应该使用一个类。

如果您使用带有变异函数的结构,该函数不应在闭包内执行变异;你不应该做以下事情:

struct ViewModel {
  var data: Int = 0

  mutating func myFunc() {
      funcWithClosure() {
          self.data = 1
      }
  }
}

If I changed ViewModel to class, didSet not called

这里没有问题 - 这是预期的行为。


如果你更喜欢使用struct,你可以这样做

  func fetchData(completion: ViewModel ->()) {
    XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
    NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: "http://stackoverflow.com")!) {
      result in
      var newViewModel = self
      newViewModel.data = 10
      print("viewModel.data in fetchResponse : \(self.data)")
      completion(newViewModel)
      XCPlaygroundPage.currentPage.finishExecution()
      }.resume()
  }


  viewModel.fetchData { newViewModel in
     self.viewModal = newViewModel
      print("viewModel.data after fetch : \(self.viewModel.data)")
    }

另请注意,提供给 dataTaskWithURL 的闭包不会在主线程上运行。您可能想在其中调用 dispatch_async(dispatch_get_main_queue()) {...}

关于Swift:ViewModel 应该是结构体还是类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37913904/

相关文章:

ios - 在我的项目中通过 pod 安装 MobileVLCKit 时显示链接器错误

swift - 调整下拉菜单的大小

sql - 查询 athena 时将结构转换为 json

c - 结构操作需要一些解释

c# - MVVM 中公共(public)属性的实践

Lua 中的结构体?

ios - 我们如何使用 `Button` 添加 `TextField` 和 `SwiftUI`

swift - 通过 Alamofire + Swift 2 发布参数的语法

windows-phone-7 - 在 View 模型中获得用户控制权

design-patterns - 为什么 mvvm 不是 mvmv 或 vvmm