当引用类型的属性具有相互较强的所有权(或具有闭包)时,会发生Swift中的引用循环。
是否有可能使用值类型 的参考周期?
我在游乐场尝试了这个但没有成功(错误:不允许递归值类型'A')。
struct A {
var otherA: A? = nil
init() {
otherA = A()
}
}
答案 0 :(得分:10)
引用周期(或保留周期)之所以如此命名,是因为它表示cycle中的object graph:
每个箭头表示一个对象retaining另一个(强引用)。除非循环被破坏,否则永远不会释放这些对象的内存。
在捕获和存储值类型(结构和枚举)时,不存在引用。值是复制,而不是引用,尽管值可以保存对象的引用。
换句话说,值可以在对象图中具有外向箭头,但没有传入箭头。这意味着他们无法参与一个周期。
答案 1 :(得分:5)
正如编译告诉你的那样,你所做的是非法的。正是因为 是一种值类型,所以没有连贯有效的方法来实现您所描述的内容。如果类型需要引用自身(例如,它具有与自身类型相同的属性),则使用类,而不是结构。
或者,您可以使用枚举,但只能以特殊的,有限的方式使用:枚举大小写关联值可以是该枚举的实例,前提是(或者整个枚举)标记为indirect
:
enum Node {
case None(Int)
indirect case left(Int, Node)
indirect case right(Int, Node)
indirect case both(Int, Node, Node)
}
答案 2 :(得分:4)
免责声明:我在这里做了一个(希望受过教育的)Swift编译器内部工作的猜测,所以应用盐粒。
除了价值语义之外,问问自己:为什么我们有结构?有什么好处?
一个优点是我们可以(读取:想要)将它们存储在堆栈(在对象框架中),即就像其他语言中的原始值一样。特别是,我们不想在堆上分配专用空间来指向。这使得访问struct值更有效:我们(读取:编译器)总是知道相对于当前帧或对象指针,它在内存中确切找到值的位置。
为了使编译器能够解决这个问题,在确定堆栈或对象框架的结构时,它需要知道给定结构值保留多少空间。只要struct值是固定大小的树(忽略对象的传出引用;它们指向堆对我们不感兴趣),这很好:编译器可以只添加它找到的所有大小。
如果你有一个递归结构,这就失败了:你可以用这种方式实现列表或二叉树。编译器无法静态地弄清楚如何在内存中存储这些值,因此我们必须禁止它们。
Nota bene:同样的推理解释了为什么结构是按值传递的:我们需要 它们在的新环境中
答案 3 :(得分:2)
您通常不能使用值类型的引用循环,因为Swift通常不允许引用值类型。一切都被复制了。
但是,如果你很好奇,你实际上可以通过在闭包中捕获self来诱导一个值类型的引用循环。
以下是一个例子。请注意,MyObject
类仅用于说明泄漏。
class MyObject {
static var objCount = 0
init() {
MyObject.objCount += 1
print("Alloc \(MyObject.objCount)")
}
deinit {
print("Dealloc \(MyObject.objCount)")
MyObject.objCount -= 1
}
}
struct MyValueType {
var closure: (() -> ())?
var obj = MyObject()
init(leakMe: Bool) {
if leakMe {
closure = { print("\(self)") }
}
}
}
func test(leakMe leakMe: Bool) {
print("Creating value type. Leak:\(leakMe)")
let _ = MyValueType(leakMe: leakMe)
}
test(leakMe: true)
test(leakMe: false)
输出:
Creating value type. Leak:true
Alloc 1
Creating value type. Leak:false
Alloc 2
Dealloc 2
答案 4 :(得分:1)
快速简便的黑客解决方法:只需将其嵌入阵列即可。
struct A {
var otherA: [A]? = nil
init() {
otherA = [A()]
}
}
答案 5 :(得分:0)
但是,是否有可能只使用值类型的参考周期?
取决于您的意思"仅限值类型"。 如果你的意思是完全没有包含隐藏内容的引用,那么答案是否定的。 要制作参考周期,您至少需要一个参考。
但是在Swift中,Array,String或其他类型是值类型,它们可能在其实例中包含引用。如果您的"值类型"包括这些类型,答案是肯定的。