这里的问题是使用UnsafeMutablePointer<SomeStruct>.memory
。重要的是不要陷入思考的陷阱,即memory
就像包含指向对象的存储属性,只要指针存在,它就会保持活动状态。即使它感觉像一个,它不是,它只是原始的记忆。
这里是一个只使用一个类一个简单的例子:
class C {
var x: Int
func f() { println(x) }
init(_ x: Int) { self.x = x; println("Created") }
deinit { println("Destroyed") }
}
let p = UnsafeMutablePointer<C>.alloc(1)
p.initialize(C(42))
p.memory.f()
p.destroy() // “Destroyed” printed here
p.dealloc(1)
// using p.memory at this point is, of course, undefined and crashy...
p.memory.f()
但是,假设你注意到memory
值的副本,并将其分配给另一个变量。这样做会增加对象memory
指出,(一样的,如果你把其他常规类的引用变量的副本的引用计数:
let p = UnsafeMutablePointer<C>.alloc(1)
p.initialize(C(42))
var c = p.memory
p.destroy() // Nothing will be printed here
p.dealloc(1)
// c has a reference
c.f()
// reassigning c decrements the last reference to the original
// c so the next line prints “Destroyed” (and “Created” for the new one)
c = C(123)
现在,假设你创建了一个捕获p
封闭,并用它的记忆之后p.destroy()
被称为:
let p = UnsafeMutablePointer<C>.alloc(1)
p.initialize(C(42))
let f = { p.memory.f() }
p.destroy() // “Destroyed” printed here
p.dealloc(1)
// this amounts to calling p.memory.f() after it's destroyed,
// and so is accessing invalid memory and will crash...
f()
但是,正如你的情况,如果你而不只是分配给p.memory.f
f
,它是完美的罚款:
let p = UnsafeMutablePointer<C>.alloc(1)
p.initialize(C(42))
var f = p.memory.f
p.destroy() // Nothing will print, because
// f also has a reference to what p’s reference
// pointed to, so the object stays alive
p.dealloc(1)
// this is perfectly fine
f()
// This next line will print “Destroyed” - reassigning f means
// the reference f has to the object is decremented, hits zero,
// and the object is destroyed
f = { println("blah") }
那么如何来f
捕获价值?
正如@rintaro指出的,Swift中的成员方法是curried函数。想象一下,没有成员方法。相反,只有常规函数和具有成员变量的结构。你怎么能写出等价的方法?你可能会做这样的事情:
// a C.f method equivalent. Using this
// because self is a Swift keyword...
func C_f(this: C) {
println(this.x)
}
let c = C(42)
// call c.f()
C_f(c) // prints 42
斯威夫特走出这一步,虽然,“咖喱”的第一个参数,这样就可以写c.f
并获得结合f
到C
特定实例的功能:
// C_f is a function that takes a C, and returns
// a function()->() that captures the this argument:
func C_f(this: C) ->()->() {
// here, because this is captured, it’s reference
// count will be incremented
return { println(this.x) }
}
let p = UnsafeMutablePointer<C>.alloc(1)
p.initialize(C(42))
var f = C_f(p.memory) // The equivalent of c.f
p.destroy() // Nothing will be destroyed
p.dealloc(1)
f = { println("blah") } // Here the C will be destroyed
这相当于在您的原始问题代码中的捕获,应该显示为什么你没有看到你原来的一个对象被销毁。
顺便说一句,如果你真的想用一个封闭的表达打电话给你的方法(假设你想要做之前或之后,更多的工作),你可以使用一个变量捕获列表:
let p = UnsafeMutablePointer<C>.alloc(1)
p.initialize(C(42))
// use variable capture list to capture p.memory
let f = { [c = p.memory] in c.f() }
p.destroy() // Nothing destroyed
p.dealloc(1)
f() // f has it’s own reference to the object
感谢您的详细解答!我的目的是将另一个类的功能保存为一个变量,而不创建一个强大的参考文献。我真的很喜欢你提到捕获列表的最后一个例子,并且如果我错了,请纠正我:让我在 c?.f() }中解决我的问题。不创建强大的参考周期(如果我正确地处理可选项)。 – 2015-02-08 15:10:31
是的你是对的,这是一个避免强循环的好方法。尽管如此,如果您确定您拥有的对象的生命周期将与封闭所有者的生命周期相匹配,您可能还想考虑“无主”而不是“弱” - 尽管这受到与指针,如果你错了一生。 – 2015-02-08 15:13:48