我试图看看我是否可以为我的模型使用结构并尝试这个。当我致电vm.testClosure()
时,它不会更改x
的值,我不知道为什么。
struct Model
{
var x = 10.0
}
var m = Model()
class ViewModel
{
let testClosure:() -> ()
init(inout model: Model)
{
testClosure =
{
() -> () in
model.x = 30.5
}
}
}
var vm = ViewModel(model:&m)
m.x
vm.testClosure()
m.x
答案 0 :(得分:3)
inout
参数不是对值类型的引用 - 它只是该值类型的卷影副本,它会被写回调用者&# 39;函数返回时的s值。
您的代码中发生的是inout
变量正在逃避函数的生命周期(通过在随后存储的闭包中捕获) - 意味着{{1}的任何更改函数返回后的变量永远不会反映在该闭包之外。
由于这种关于inout
参数的常见误解,been a Swift Evolution proposal只允许inout
个句点捕获inout
个参数。从Swift 3开始,您当前的代码将不再编译。
如果您确实需要传递代码中的引用 - 那么您应该使用引用类型(将@noescape
设为Model
)。虽然我怀疑你可能能够重构你的逻辑以避免在第一时间传递引用(但是没有看到你的实际代码,它是不可能建议的。)
(编辑>自发布此答案以来,class
参数现在可以编译为传递引用,可以通过查看发出的SIL或IR来查看。由于无法保证无论哪个在函数调用后调用者的值仍然有效,因此您无法对其进行处理。)
答案 1 :(得分:0)
闭包的实例将获得它自己的,独立的捕获值副本,只有它可以改变。在执行闭包时捕获该值。让我们看看你稍微修改过的代码
struct Model
{
var x = 10.0
mutating func modifyX(newValue: Double) {
let this = self
let model = m
x = newValue
// put breakpoint here
//(lldb) po model
//▿ Model
// - x : 30.0
//
//(lldb) po self
//▿ Model
// - x : 301.0
//
//(lldb) po this
//▿ Model
// - x : 30.0
}
}
var m = Model()
class ViewModel
{
let testClosure:() -> ()
init(inout model: Model)
{
model.x = 50
testClosure =
{ () -> () in
model.modifyX(301)
}
model.x = 30
}
}
let mx = m.x
vm.testClosure()
let mx2 = m.x
答案 2 :(得分:0)
这就是Apple所说的。
值类型是在分配给a时复制的类型 变量或常量,或传递给函数时。 [...]全部 结构和枚举是Swift中的值类型
结构和枚举是值类型。默认情况下,无法在其实例方法中修改值类型的属性。
但是,如果您需要修改结构的属性或 在特定方法中枚举,您可以选择进行变异 该方法的行为。然后该方法可以变异(即, 改变)方法中的属性,以及它的任何变化 当方法结束时,make会被写回原始结构。 该方法还可以为其隐式分配一个全新的实例 自我属性,这个新实例将取代现有的实例 当方法结束时。
取自here