类和结构闭包中的Swift可变结构表现不同 [英] Swift mutable structs in closure of class and struct behave differently

查看:173
本文介绍了类和结构闭包中的Swift可变结构表现不同的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个具有结构变量(S)的类(A)。在这个类的一个函数中,我在struct变量上调用一个mutating函数,这个函数需要一个闭包。这个闭包的主体检查struct变量的name属性。

I have a class(A) that has a struct variable (S). In one function of this class I call a mutating function on struct variable,this function takes a closure. Body of this closure checks the struct variable's name property.

struct的变异函数依次调用某个类(B)的函数。这个类的功能再次关闭。在这个闭包的主体中改变结构,即更改name属性,并调用第一个类提供的闭包。

Struct's mutating function in turns calls a function of some class(B). This class's function again takes a closure. In this closure's body mutate the struct, i.e. change the name property, and call the closure that was supplied by the first class.

当第一个类(A)闭包时我们正在检查struct的name属性,它永远不会被更改。

When the first class (A) closure is called where we are inspecting the struct's name property, it is never changed.

但是如果我使用结构(C)代替步骤2在B类中,我看到A类的闭包结构实际上已经改变了。下面是代码:

But in step 2 if I use a struct (C) instead of class B, I see that inside class A's closure struct is actually changed. Below is the code:

class NetworkingClass {
  func fetchDataOverNetwork(completion:()->()) {
    // Fetch Data from netwrok and finally call the closure
    completion()
  }
}

struct NetworkingStruct {
  func fetchDataOverNetwork(completion:()->()) {
    // Fetch Data from netwrok and finally call the closure
    completion()
  }
}

struct ViewModelStruct {

  /// Initial value
  var data: String = "A"

  /// Mutate itself in a closure called from a struct
  mutating func changeFromStruct(completion:()->()) {
    let networkingStruct = NetworkingStruct()
    networkingStruct.fetchDataOverNetwork {
      self.data = "B"
      completion()
    }
  }

  /// Mutate itself in a closure called from a class
  mutating func changeFromClass(completion:()->()) {
    let networkingClass = NetworkingClass()
    networkingClass.fetchDataOverNetwork {
      self.data = "C"
      completion()
    }
  }
}

class ViewController {
  var viewModel: ViewModelStruct = ViewModelStruct()

  func changeViewModelStruct() {
    print(viewModel.data)

    /// This never changes self.viewModel inside closure, Why Not?
    viewModel.changeFromClass {
      print(self.viewModel.data)
    }

    /// This changes self.viewModel inside/outside closure, Why?
    viewModel.changeFromStruct {
      print(self.viewModel.data)
    }
  }
}

var c = ViewController()
c.changeViewModelStruct()

为什么会出现这种不同的行为。我认为区别因素应该是我是使用viewModel的结构还是类。但这取决于Networking是一个类还是结构,它独立于任何ViewController或ViewModel。任何人都可以帮我理解这个吗?

Why this different behaviour. I thought the differentiating factor should be whether I use a struct for viewModel or a class. But here it is depending upon whether Networking is a class or structure, that is independent of any ViewController or ViewModel. Can anyone help me understand this?

推荐答案

这个怎么样?

import Foundation
import XCPlayground


protocol ViewModel {
  var delegate: ViewModelDelegate? { get set }
}

protocol ViewModelDelegate {
  func viewModelDidUpdated(model: ViewModel)
}

struct ViewModelStruct: ViewModel {
  var data: Int = 0
  var delegate: ViewModelDelegate?

  init() {
  }

  mutating func fetchData() {
    XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
    NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: "http://stackoverflow.com")!) {
       result in
      self.data = 20
      self.delegate?.viewModelDidUpdated(self)
      print("viewModel.data in fetchResponse : \(self.data)")

      XCPlaygroundPage.currentPage.finishExecution()
      }.resume()
  }
}

protocol ViewModeling {
  associatedtype Type
  var viewModel: Type { get }
}

typealias ViewModelProvide = protocol<ViewModeling, ViewModelDelegate>

class ViewController: ViewModelProvide {
  var viewModel = ViewModelStruct() {
    didSet {
      viewModel.delegate = self
      print("ViewModel in didSet \(viewModel)")
    }
  }

  func viewDidLoad() {
    viewModel = ViewModelStruct()
  }

  func changeViewModelStruct() {
    print(viewModel)
    viewModel.fetchData()
  }
}

extension ViewModelDelegate where Self: ViewController {
  func viewModelDidUpdated(viewModel: ViewModel) {
    self.viewModel = viewModel as! ViewModelStruct
  }
}

var c = ViewController()
c.viewDidLoad()
c.changeViewModelStruct()

在解决方案2,3中,需要在ViewController中分配新的View Model。所以我想通过使用Protocol Extension自动创建它。 didSet观察者运作良好!但这需要在委托方法中删除强制转换。

In your solution 2, 3, it need to assign new View Model in ViewController. So I wanna make it automatically by using Protocol Extension. didSet observer works well! But this need to remove force casting in delegate method.

这篇关于类和结构闭包中的Swift可变结构表现不同的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆