Pau*_*aul 14 struct closures mvvm swift
我试图在我的新项目中使用MVVM模式.第一次,我创建了我的所有视图模型到struct.但是当我使用闭包实现异步业务逻辑(如fetchDataFromNetwork)时,闭包会捕获旧的视图模型值,然后更新到那个.不是新的视图模型值.
这是操场上的测试代码.
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()
Run Code Online (Sandbox Code Playgroud)
控制台打印
viewModel.data before fetch : 0
viewModel.data in didSet : 0
viewModel.data in fetchResponse : 10
viewModel.data after fetch : 0
Run Code Online (Sandbox Code Playgroud)
问题是ViewController中的View Model没有新的Value 10.
如果我将ViewModel更改为类,则未调用didSet,但ViewController中的View Model具有新值10.
你应该使用一个类.
如果使用具有变异函数的结构,则该函数不应在闭包内执行变异; 你应该没有做到以下几点:
struct ViewModel {
var data: Int = 0
mutating func myFunc() {
funcWithClosure() {
self.data = 1
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果我将ViewModel更改为class,则不调用didSet
这里没有错 - 这是预期的行为.
如果您愿意使用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)")
}
Run Code Online (Sandbox Code Playgroud)
另请注意,提供的闭包dataTaskWithURL不会在主线程上运行.你可能想要打电话dispatch_async(dispatch_get_main_queue()) {...}.
| 归档时间: |
|
| 查看次数: |
4080 次 |
| 最近记录: |