一个比较少见的循环引用

循环引用应该大部分人都知道怎么回事.

较常见的就有

  • A实例 强引用 B实例, B 强引用 A.
  • A实例强引用 Block B, B 里面 调用了self

在开发的时候发现另一个类型, 不过有点类似上述的第二个

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import Foundation
class Person {

var info: Info?

struct Info {
var name: String
var family: String
var age: Int
}

func printInfo() {
if let info = info {
print(info)
}
}

func transform() -> Info {
self.info = Info(
name: "吴彦祖",
family: "吴氏家族",
age: 20
)
return self.info!
}

deinit {
print("deinit")
}
}

let block = {
print("begin")
let p = Person()
p.transform()
print(CFGetRetainCount(p as CFTypeRef))
print("end")
}
block()

上述代码 run 一下 结果如下,

1
2
3
4
begin
2
end
deinit

打印 deinit 了,说明 p 正常释放了, 没有循环引用

然后现在改一下 Struct Info 和 transform 方法, 在里面添加 prinfFunc 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct Info {
var name: String
var family: String
var age: Int
var printFunc: () -> ()
}
func transform() -> Info {
return Info(
name: "吴彦祖",
family: "吴氏家族",
age: 20,
printFunc: printInfo
)
}

再次 run 一下, 打印结果如下

1
2
3
4
begin
3
end
deinit

依旧可以打印出 deinit, 但是 p 的引用计数 +1.
说明在 struct 里面持有 某实例的方法会让该实例引用计数 +1.

现在如果把 transform 调整如下, 返回 info 之前让 赋值给 self.info

1
2
3
4
5
6
7
8
9
func transform() -> Info {
self.info = Info(
name: "吴彦祖",
family: "吴氏家族",
age: 20,
printFunc: printInfo
)
return self.info!
}

打印如下:

1
2
3
begin
3
end

这一次没有 deinit, p 没有被释放, 形成了循环引用.
造成这个循环主要是没想到 struct 里面持有方法, 也会造成计数 +1.


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!