mirror of
https://github.com/NohamR/knowledge-kit.git
synced 2026-05-25 12:27:15 +00:00
update: 动态库、静态库的编译链接细节
This commit is contained in:
@@ -1,6 +1,188 @@
|
||||
# 内存管理
|
||||
|
||||
|
||||
## 弱引用
|
||||
Swift 和 OC 都是通过引用计数方式来管理内存的。
|
||||
|
||||
Swift 的 ARC 存在3种情况:
|
||||
|
||||
- 强引用(strong reference)。默认情况下,都是强引用。
|
||||
当一个强指针离开作用域后,会自动释放对象,调用 deinit 方法。
|
||||
```swift
|
||||
class Person {
|
||||
deinit {
|
||||
print("Person deinit")
|
||||
}
|
||||
}
|
||||
|
||||
func test () {
|
||||
let p: Person = Person()
|
||||
}
|
||||
|
||||
print("1")
|
||||
test()
|
||||
print("2")
|
||||
// console
|
||||
1
|
||||
Person deinit
|
||||
2
|
||||
```
|
||||
|
||||
- 弱引用(weak reference)。通过 weak 定义弱引用。**必须是可选类型,因为实例销毁后,ARC 会自动将弱引用设置为 nil**。
|
||||
```swift
|
||||
weak var p: Person? = Person()
|
||||
```
|
||||
- 弱引用如果被设置为 nil,是不会触发属性观察器的 willSet、didSet 方法的
|
||||
```swift
|
||||
class Dog {
|
||||
deinit {
|
||||
print("Dog deinit")
|
||||
}
|
||||
}
|
||||
|
||||
class Person {
|
||||
weak var dog: Dog? {
|
||||
willSet {
|
||||
print("willSet")
|
||||
}
|
||||
didSet {
|
||||
print("didSet")
|
||||
}
|
||||
}
|
||||
deinit {
|
||||
print("Person deinit")
|
||||
}
|
||||
}
|
||||
|
||||
func test () {
|
||||
let p: Person = Person()
|
||||
p.dog = Dog()
|
||||
print(p)
|
||||
}
|
||||
|
||||
|
||||
print("1")
|
||||
test()
|
||||
print("2")
|
||||
// console
|
||||
1
|
||||
willSet // 这里的触发是 test 方法里,给 person 对象设置了 dog 属性时触发的。但是 weak 指针设置为 nil 的时候没有触发属性观察器
|
||||
didSet
|
||||
Dog deinit
|
||||
SwiftDemo.Person
|
||||
Person deinit
|
||||
2
|
||||
```
|
||||
换一种写法。可以发现在 init 方法里面,属性观察器 willSet、didSet 是不会触发的。
|
||||
```swift
|
||||
class Dog {
|
||||
deinit {
|
||||
print("Dog deinit")
|
||||
}
|
||||
}
|
||||
|
||||
class Person {
|
||||
|
||||
weak var dog: Dog? {
|
||||
willSet {
|
||||
print("willSet")
|
||||
}
|
||||
didSet {
|
||||
print("didSet")
|
||||
}
|
||||
}
|
||||
|
||||
init (dog: Dog?) {
|
||||
self.dog = dog
|
||||
}
|
||||
deinit {
|
||||
print("Person deinit")
|
||||
}
|
||||
}
|
||||
|
||||
func test () {
|
||||
let p: Person = Person(dog: Dog())
|
||||
print(p)
|
||||
}
|
||||
|
||||
|
||||
print("1")
|
||||
test()
|
||||
print("2")
|
||||
// console
|
||||
1
|
||||
Dog deinit
|
||||
SwiftDemo.Person
|
||||
Person deinit
|
||||
2
|
||||
```
|
||||
- 无主引用(unowned reference)。通过 unowned 定义无主引用
|
||||
- 不会产生强引用,非可选类型。实例销毁后仍然存储着实例的内存地址,类似 OC 的 `unsafe_retained`
|
||||
- 如果在实例销毁后访问无主引用,会产生野指针错误
|
||||
|
||||
|
||||
weak、unowned 只能用在类实例上。比如:
|
||||
```swift
|
||||
protocol Liveavle: AnyObject { }
|
||||
class Person { }
|
||||
|
||||
weak var p1: Person?
|
||||
weak var p2: AnyObject?
|
||||
weak var p3: Liveavle?
|
||||
|
||||
unowned var p4: Person?
|
||||
unowned var p5: AnyObject?
|
||||
unowned var p6: Liveavle?
|
||||
```
|
||||
|
||||
|
||||
## 循环引用
|
||||
weak、unowned 都能解决循环引用问题。但是 weak 由于当对象释放后,会把指针设置为 nil。所以 unowned 会比 weak 的性能更好。
|
||||
- 在生命周期中对象可能会变为 nil,推荐使用 weak
|
||||
- 初始化赋值后再也不会变为 nil 的对象,推荐使用 unowned
|
||||
|
||||
## 闭包的循环引用
|
||||
<img src="./../assets/SwiftBlockRetainCycle.png" style="zoom:40%">
|
||||
上面的代码会发生循环引用,会导致局部变量的 p 无法释放(看不到 Person 的 deinit 方法调用)
|
||||
|
||||
解法:
|
||||
- **在闭包表达式的捕获列表声明 weak 或者 unowned 引用,解决循环引用的问题**
|
||||
因为在闭包里,声明的捕获列表中将 p 用 weak 修饰,所以可以为 nil。p 使用到的地方必须用 `p?.run()`
|
||||
```swift
|
||||
class Person {
|
||||
var fn:(() -> ())?
|
||||
func run () { print("run") }
|
||||
deinit { print("deinit") }
|
||||
}
|
||||
|
||||
func test () {
|
||||
let p = Person()
|
||||
p.fn = {
|
||||
[weak p] in
|
||||
p?.run()
|
||||
}
|
||||
}
|
||||
|
||||
test()
|
||||
// deinit
|
||||
```
|
||||
另一种写法
|
||||
```swift
|
||||
p.fn = {
|
||||
[unowned p] in
|
||||
p.run()
|
||||
}
|
||||
```
|
||||
-
|
||||
```swift
|
||||
class Person {
|
||||
lazy var fn:() -> () = {
|
||||
self.run()
|
||||
}
|
||||
func run () { print("run") }
|
||||
deinit { print("deinit") }
|
||||
}
|
||||
```
|
||||
|
||||
## @escaping
|
||||
|
||||
@@ -169,7 +351,7 @@ print(age)
|
||||
|
||||
- `changeValue1` 的参数是不可变的指针,所以方法内部去修改值,编译器会报错
|
||||
- `changeValue2` 的参数是可变的指针,所以方法内部去修改值,编译没问题
|
||||
- 指针加了范型,访问真实的值可以通过 `指针.pointee` 去访问
|
||||
- 指针加了泛型,访问真实的值可以通过 `指针.pointee` 去访问
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user