📦 weihanglo / legacy-notes

📄 ios-weak_strong_unowned.md · 84 lines
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84# [iOS] Weak, Strong, Unowned 比較

#### ARC (Automatic Reference Counting)

Apple的自動記憶體管理技術,簡單來說就是:

> 在無任何 variable, constant 或 property 有**strong reference** 到該類別實例時(reference count == 0),該實例的記憶體空間就會被釋放。
> 一般情況下,variable,constant 或 property皆以 strong reference 到類別實例 (Swift)


#### Strong

就是一個pointer,會將 reference count +1,保護該object 不被ARC釋放。
在swift中用let 宣告的變數皆為 strong reference

#### Weak

- 宣告的變數需是一個可選值 Optional
- reference count 不會 +1
- 若只剩此 weak reference 到該instance,將立刻被釋放(和有GC的語言不一樣,不會留有cache)
- **swift** 中 weak reference 需以變數 **var** 宣告(因為需為Optional)

```swift
// this will failed to compile
weak let toCompiled = "failed"
```

#### Unowned

與weak相同,唯一的差異是uonwed非Optional,通常用於確定在使用unowned reference時,被referred 的物件不會變成nil

> unowned _對映到 objc 的_ `unsafe_unretained`


#### Swift 在 closure 中宣告 **capture list** 的 reference type

因 closure 本身和class一樣是 **reference types** 而非 **value types**,且有 capture 的特性,易產生 strong reference,需要設 `weak` 或 `unowned`,例如

```swift
{ [unowned self, weak delegate = self.delegate!] (parameter) -> Void in
    self.doSomething()
    variable.doAnotherThing()
}
```

兩句話說明 unowned V.S weak 在closure中的使用時機:

> If self could be nil in the closure use [weak self].
> If self will never be nil in the closure use [unowned self].

#### strongSelf 的用處

- 使用時機:當reference到的instance需要在 block的生命週期中被retain時。
- 使用實例: asynchronous downloading?
- 說明:self若被deunrefernce,strongSelf會繼續retain self 直到 block結束。若是weak reference,self很可能在afterDownload()之前被release。

```objective-c
__weak typeof(self) weakSelf = self

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
    __strong typeof(self) strongSelf = weakSelf
    if (strongSelf) {
        strongSelf.startDownload()
        strongSelf.afterDownload()
    }
})
```

```swift
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGORUND, 0)){ [weak self] in
    if let strongSelf = self {
        storngSelf.startDownload()
        strongSelf.afterDownload()
    }
}
```


#### deinit/dealloc

在該 class instance 將從記憶體釋放時,會叫這一支method,可用來做一些釋放前的 finialize工作(例如remove notification)。

若存在retain cycle,reference count 無法歸零,則不會呼叫`deinit`/`dealloc`