Swift mutable structs in closure of class and struct behave differently

后端 未结 3 941
攒了一身酷
攒了一身酷 2021-02-05 18:02

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

3条回答
  •  北恋
    北恋 (楼主)
    2021-02-05 18:44

    This is not a solution but with this code we can see that the ViewController's, viewModel.data is properly set for both class and struct cases. What is different is that the viewModel.changeFromClass closure captures a stale self.viewModel.data. Notice in particular that only the '3 self' print for class is wrong. Not the '2 self' and '4 self' prints wrapping it.

    class NetworkingClass {
      func fetchDataOverNetwork(completion:()->()) {
        // Fetch Data from netwrok and finally call the closure
        print("\nclass: \(self)")
        completion()
      }
    }
    
    struct NetworkingStruct {
      func fetchDataOverNetwork(completion:()->()) {
        // Fetch Data from netwrok and finally call the closure
        print("\nstruct: \(self)")
        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 {
          print("1 \(self)")
          self.data = "B"
          print("2 \(self)")
          completion()
          print("4 \(self)")
        }
      }
    
      /// Mutate itself in a closure called from a class
      mutating func changeFromClass(completion:()->()) {
        let networkingClass = NetworkingClass()
        networkingClass.fetchDataOverNetwork {
          print("1 \(self)")
          self.data = "C"
          print("2 \(self)")
          completion()
          print("4 \(self)")
        }
      }
    }
    
    class ViewController {
      var viewModel: ViewModelStruct = ViewModelStruct()
    
      func changeViewModelStruct() {
        print(viewModel.data)
    
        /// This never changes self.viewModel, Why Not?
        viewModel.changeFromClass {
          print("3 \(self.viewModel)")
          print(self.viewModel.data)
        }
    
        /// This changes self.viewModel, Why?
        viewModel.changeFromStruct {
          print("3 \(self.viewModel)")
          print(self.viewModel.data)
        }
      }
    }
    
    var c = ViewController()
    c.changeViewModelStruct()
    

提交回复
热议问题