Weak self - ehrldyd15/Swift_Skills GitHub Wiki
[weak self]์ ํ์ฉ ๋ฐ ํ์์ฑ
Automatic Reference Counting
Swift์ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ๋ ARC(Automatic Reference Counting)์ ์ํด ์ฒ๋ฆฌ๋๋ค.
ARC๋ ๋ ์ด์ ํ์ํ์ง ์์ ํด๋์ค ์ธ์คํด์ค์์ ์ฌ์ฉํ๋ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํด์ ํ๊ธฐ ์ํด ์๋ํ๋ค.
ARC๋ ๋๋ถ๋ถ ์์ฒด์ ์ผ๋ก ์๋ํ์ง๋ง ๋๋ก๋ ๊ฐ์ฒด ๊ฐ์ ๊ด๊ณ๋ฅผ ๋ช ํํ ํ๊ธฐ ์ํด ์ถ๊ฐ ์ ๋ณด๋ฅผ ์ ๊ณตํด์ผ ํ๋ค.
์๋ฅผ ๋ค์ด, ์์ฑ(property)์ Parent Controller์ ๋ํ ์ฐธ์กฐ(reference)๋ฅผ ์ ์ฅํ๋ Child Controller๊ฐ ์๋ ๊ฒฝ์ฐ
์ํ ์ฐธ์กฐ(Retain Cycle)๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด ํด๋น ์์ฑ(property)์ weak ํค์๋๋ก ํ์ํด์ผ ํ๋ค.
๋ฉ๋ชจ๋ฆฌ ๋์(Memory Leak)๊ฐ ์์ฌ๋๋ ๊ฒฝ์ฐ ๋ค์ ์์ ์ ์ํ ํ ์ ์๋ค.
- ๊ฐ์ฒด๊ฐ ํด์ (dismissed)๋ ํ deinitializer callback ์ฐพ๊ธฐ.
- Optional ๊ฐ์ฒด๊ฐ ์๋ ๊ฒฝ์ฐ ํด์ (dismissed) ํ ๊ฐ์ฒด๊ฐ nil์ธ์ง ํ์ธ.
- ์ฑ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ ๊ด์ฐฐํ์ฌ ๊พธ์คํ ์ฆ๊ฐํ๋์ง ํ์ธ.
- Leaks and Allocations Instruments ์ฌ์ฉ.
1. [unowned self]์ [weak self]์ค ์ด๋ค๊ฒ์ ์จ์ผํ ๊น?
[unowned self]
ํด๋ก์ ๋ ์ ์๋ ์ปจํ ์คํธ์์ ๋ชจ๋ ์์ ๋๋ ๋ณ์๋ฅผ ๊ฐ๋ ฅํ๊ฒ ์บก์ณํ ์ ์๋ค.
์๋ฅผ ๋ค์ด, ํด๋ก์ ๋ด์์ self๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ ํด๋ก์ ๋ฒ์(scope)์ ์๋ช ๊ธฐ๊ฐ ๋์ self์ ๋ํ strong reference๋ฅผ ์ ์งํ๋ค.
self๊ฐ ์ด ํด๋ก์ ์ ๋ํ ์ฐธ์กฐ๋ฅผ ์ ์งํ๋ ๊ฒฝ์ฐ(๋ฏธ๋ ์ด๋ ์์ ์ ํธ์ถํ๊ธฐ ์ํด) strong reference cycle์ ๊ฐ๊ฒ ๋๋ค.
unowned์ ์์ ๊ฐ์ ์ํ ์ฐธ์กฐ๋ฅผ ํผํ๊ธฐ ์ํด ์ฌ์ฉํ ์ ์๋ ๋ฐฉ๋ฒ ์ค ํ๋์ด๋ค.
unowned์ ์ํ ์ฐธ์กฐ๋ฅผ ํผํ ์ ์๊ฒ ํ๋ ๊ณผ์ ์์ self๋ฅผ ๊ฐ์ ๋ก unwrappingํ๊ณ ํ ๋น์ด ํด์ ๋ ํ์๋ ๋ด์ฉ์ ์ก์ธ์คํ๋ ค๊ณ ์๋ํ๋ค.
๋ฐ๋ผ์ ์์ ํ์ง ์์ ๋ฐฉ๋ฒ์ด๋ค.
[weak self]
weak๋ ์ํ ์ฐธ์กฐ๋ฅผ ํผํ ์ ์๊ฒ ํ๋ ๊ณผ์ ์์ self๋ฅผ Optional๋ก ๋ง๋ ๋ค.
Optional Chaining(ex: self?.)์ ์ฌ์ฉํ ์๋ ์์ง๋ง ๋ ๋๋ฆฌ ์ฌ์ฉ๋๊ณ ์๋ ๋ฐฉ์์
guard let ๊ตฌ๋ฌธ์ ์ฌ์ฉํด ํด๋ก์ ์์ ์ self์ ๋ํ ์์ ๊ฐํ ์ฐธ์กฐ๋ฅผ ๋ง๋๋ ๊ฒ์ด๋ค.
// Example
guard let self = self else { return }
// Swift 4.2๋ถํฐ, guard let self = self ๊ตฌ๋ฌธ์ ๋ํ ๊ณต์ ์ง์์ด ์ถ๊ฐ๋์ด ์ด๊ฒ์ด ๊ฐ๋ฅํด์ก๋ค.
Optional ์ฒ๋ฆฌ๋ฅผ ํผํ๊ธฐ ์ํด weak๋ณด๋ค unowned๋ฅผ ์ฌ์ฉํ๊ณ ์ถ๋ค๋ฉด ํด๋ก์ ์คํ ์ค์ ์ฐธ์กฐ๊ฐ ์ ๋ nil์ด ๋์ง ์์ ๊ฒ์ด๋ผ๊ณ ํ์ ํ ๋๋ง unowned๋ฅผ ์ฌ์ฉํด์ผ ํ๋ค.
unowned๋ optional์ ๊ฐ์ ๋ก unwrappingํ๋ ๊ฒ๊ณผ ๊ฐ์ผ๋ฉฐ, nil์ด ๋๋ฉด ์ถฉ๋์ด ๋ฐ์ํ๋ค.
๋ฐ๋ผ์ [weak self]๊ฐ ํจ์ฌ ๋ ์์ ํ ๋์์ด๋ค.
2. Non-escaping closure vs. Escaping closure
[weak self]๊ฐ ํจ์ฌ ์์ ํ๋ค๋ ์ฌ์ค์ ํ์ธํ์ผ๋ ๋ชจ๋ ํด๋ก์ ์์ [weak self]๋ฅผ ์ฌ์ฉํด์ผ ํ ๊น?
[Non-escaping closure]
Non-escaping closure๋ ๋ฒ์(scope) ๋ด์์ ์คํ๋๋ค.
์ฆ, ์ฝ๋๋ฅผ ์ฆ์ ์คํํ๊ณ ๋์ค์ ์ ์ฅํ๊ฑฐ๋ ์คํํ ์ ์๋ค.
Non-escaping closure(์: compactMap๊ณผ ๊ฐ์ ๊ณ ์ฐจ ํจ์)๋ ๊ฐ๋ ฅํ ์ฐธ์กฐ ์ฃผ๊ธฐ๋ฅผ ๋์ ํ ์ํ์ด ์์ผ๋ฏ๋ก
weak ๋๋ unowned๋ฅผ ์ฌ์ฉํ ํ์๊ฐ ์๋ค.
[Escaping closure]
Escaping closure๋ ์ ์ฅ๋ ์ ์๊ณ ๋ค๋ฅธ ํด๋ก์ ๋ก ์ ๋ฌ๋ ์ ์์ผ๋ฉฐ ๋ฏธ๋์ ์ด๋ ์์ ์ ์คํ๋ ์ ์๋ค.
Escaping closure๋ ๋ค์ ๋ ์กฐ๊ฑด์ด ๋ชจ๋ ์ถฉ์กฑ๋๋ ๊ฒฝ์ฐ์ weak ๋๋ unowned๋ฅผ ์ฌ์ฉํ๋ค.
-
ํด๋ก์ ๋ ์์ฑ์ ์ ์ฅ๋๊ฑฐ๋ ๋ค๋ฅธ ํด๋ก์ ๋ก ์ ๋ฌ๋๋ค.
-
ํด๋ก์ ๋ด๋ถ์ ๊ฐ์ฒด(์: self)๋ ํด๋ก์ (๋๋ ์ ๋ฌ๋ ๋ค๋ฅธ ํด๋ก์ )์ ๋ํ ๊ฐ๋ ฅํ ์ฐธ์กฐ๋ฅผ ์ ์งํ๋ค.
[Delayed Deallocation]
Delayed Deallocation๋ Escaping ๋ฐ Non-escaping ํด๋ก์ ์์ ๋ํ๋๋ ๋ถ์์ฉ์ด๋ค.
์ ํํ ๋ฉ๋ชจ๋ฆฌ ๋์๋ ์๋์ง๋ง ์ํ์ง ์๋ ๋์์ผ๋ก ์ด์ด์ง ์ ์๋ค.
(ex: Controller๋ฅผ ํด์ฒดํ์ง๋ง ๋ณด๋ฅ ์ค์ธ ๋ชจ๋ ํด๋ก์ ์์ ์ด ์๋ฃ๋ ๋๊น์ง ๋ฉ๋ชจ๋ฆฌ๊ฐ ํด์ ๋์ง ์์)
๊ธฐ๋ณธ์ ์ผ๋ก ํด๋ก์ ๋ ๋ณธ๋ฌธ์์ ์ฐธ์กฐํ๋ ๋ชจ๋ ๊ฐ์ฒด๋ฅผ ๊ฐ๋ ฅํ๊ฒ ์บก์ฒํ๊ธฐ ๋๋ฌธ์ ํด๋ก์ ๋ณธ๋ฌธ์ด๋ ๋ฒ์๊ฐ ์ด์์๋ ํ ๊ฐ์ฒด๊ฐ ๋ฉ๋ชจ๋ฆฌ์์ ํ ๋น ํด์ ๋๋ ๊ฒ์ ๋ฐฉํดํ๋ค.
์ด ๊ฒฝ์ฐ Escaping ๋ฐ Non-escaping ํด๋ก์ ๋ชจ๋ [weak self]๋ฅผ ์ฌ์ฉํด Delayed Deallocation๋ฅผ ๋ฐฉ์งํ ์ ์๋ค.
([weak unowned]๋ฅผ ์ฌ์ฉํ๋ค๋ฉด ์ถฉ๋์ ์ผ์ผํค๊ฒ ๋ ๊ฒ์ด๋ค.)
3. โguard let self = selfโ vs. Optional Chaining
[weak self]๋ฅผ ์ฌ์ฉํ ๋ Optional Chaining(ex: self?.)์ ์ฌ์ฉํ์ฌ
self์ ์ก์ธ์คํ๋ ๋์ guard let self = self๋ฅผ ์ฌ์ฉํ๋ฉด ๋ฐ์ํ๋ ์ ์ฌ์ ์ธ ๋ถ์์ฉ์ด ์๋ค.
[โguard let self = self else { return }โ]
Delayed Deallocation๊ฐ ๋ํ๋ ์ ์๋ ํด๋ก์ ์์ 'guard let self = self' ๊ตฌ๋ฌธ์ ์ฌ์ฉํ๋ค๋ฉด Delayed Deallocation๋ฅผ ๋ฐฉ์งํ ์ ์๋ค.
์ฌ๊ธฐ์ 'guard let' ๊ตฌ๋ฌธ์ด ํ๋ ์ผ์ self๊ฐ nil๊ณผ ๊ฐ์์ง ์ฌ๋ถ๋ฅผ ํ์ธํ๊ณ , ๊ทธ๋ ์ง ์์ ๊ฒฝ์ฐ ๋ฒ์ ๊ธฐ๊ฐ ๋์ self์ ๋ํ ์ผ์์ ์ธ ๊ฐ๋ ฅํ ์ฐธ์กฐ๋ฅผ ์์ฑํ๋ ๊ฒ์ด๋ค.
๋ค์ ๋งํ๋ฉด, 'guard let' ๊ตฌ๋ฌธ์ ํด๋ก์ ์ ์๋ช ๋์ self๊ฐ ํ ๋น ํด์ ๋๋ ๊ฒ์ ๋ฐฉ์งํด self๊ฐ ์ ์ง๋๋๋ก ๋ณด์ฅํ๋ค.
['self?.']
'guard let' ๊ตฌ๋ฌธ์ ์ฌ์ฉํ์ง ์๊ณ ๋์ Optional Chaining(ex: self?.)์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ
ํด๋ก์ ๊ฐ ์์ํ ๋ ๊ฐ๋ ฅํ ์ฐธ์กฐ๋ฅผ ๋ง๋๋ ๋์ ๋ชจ๋ ๋ฉ์๋ ํธ์ถ์์ self์ ๋ํ nil ๊ฒ์ฌ๋ฅผ ์งํํ๋ค.
์ฆ, ํด๋ก์ ์คํ ์ค ์ด๋ ์์ ์์ self๊ฐ nil์ด ๋๋ฉด ์๋์ผ๋ก ํด๋น ๋ฉ์๋ ํธ์ถ์ ๊ฑด๋๋ฐ๊ณ ๋ค์ ์ค๋ก ์ด๋ํ๋ค.
guard let' ๊ตฌ๋ฌธ์ ๊ฒฝ์ฐ์ ๋ฐ๋ผ Delayed Deallocation๋ก ์ด์ด์ง ์ ์๋ค.
๋๋ฌธ์ ๊ฒฝ์ฐ์ ๋ฐ๋ผ 'guard let' ๋ฐ 'Optional Chaining' ์ค ์ด๋ค ๊ตฌ๋ฌธ์ ์ฌ์ฉํด์ผ ํ ์ง ์๊ฐํ ํ์๊ฐ ์๋ค.
-
ViewController๊ฐ ํด์ (dismiss)๋ ํ ๋ถํ์ํ ์์ ์ ํผํ๋ ค๋ ๊ฒฝ์ฐ
-
๊ฐ์ฒด๊ฐ ํ ๋น ํด์ ๋๊ธฐ ์ ๋ชจ๋ ์์ ์ด ์๋ฃ๋์๋์ง ํ์ธํ๋ ค๋ ๊ฒฝ์ฐ(์: ๋ฐ์ดํฐ ์์ ๋ฐฉ์ง๋ฅผ ์ํด)
4. Common situations where [weak self] may or may not be needed.
[weak self]๊ฐ ํ์ํ ์๋ ์๊ณ ํ์ํ์ง ์์ ์๋ ์๋ ์ผ๋ฐ์ ์ธ ์ํฉ ๋ช ๊ฐ์ง๊ฐ ์๋ค.
[Grand Central Dispatch(GCD)]
GCD ํธ์ถ์ ๋์ค์ ์คํํ๊ธฐ ์ํด ์ ์ฅํ์ง ์๋ ํ ์ํ์ฐธ์กฐ์ ์ํ์ด ์๋ค.
// ์๋ฅผ ๋ค์ด, ์ด๋ฌํ ํธ์ถ์ [weak self] ์์ด๋ ์ฆ์ ์คํ๋๊ธฐ ๋๋ฌธ์ ๋ฉ๋ชจ๋ฆฌ ๋์๋ฅผ ์ผ์ผํค์ง ์๋๋ค.
func nonLeakyDispatchQueue() {
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
self.view.backgroundColor = .red
}
DispatchQueue.main.async {
self.view.backgroundColor = .red
}
DispatchQueue.global(qos: .background).async {
print(self.navigationItem.description)
}
}
// ๊ทธ๋ฌ๋ ๋ค์ DispatchWorkItem์ ์์ฑ(property)์ ์ ์ฅํ๊ณ [weak self] ํค์๋ ์์ด ํด๋ก์ ๋ด๋ถ์์ self๋ฅผ ์ฐธ์กฐํ๊ธฐ ๋๋ฌธ์ ๋ฉ๋ชจ๋ฆฌ ๋์๊ฐ ๋ฐ์ํ๋ค.
func leakyDispatchQueue() {
let workItem = DispatchWorkItem {
self.view.backgroundColor = .red
}
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0,
execute: workItem)
self.workItem = workItem // stored in a property
}
[UIView.Animate ๋ฐ UIViewPropertyAnimator]
GCD์ ๋ง์ฐฌ๊ฐ์ง๋ก ์ ๋๋ฉ์ด์ ํธ์ถ๋ ์์ฑ(property)์ UIViewPropertyAnimator๋ฅผ ์ ์ฅํ์ง ์๋ ํ ์ํ์ฐธ์กฐ์ ์ํ์ด ์๋ค.
// ์๋ฅผ ๋ค์ด ๋ค์ ํธ์ถ์ ์์ ํ๋ค.
func animteToRed() {
UIView.animate(withDuration: 3.0) {
self.view.backgroundColor = .red
}
}
// ๋ฐ๋ฉด์ ๋ค์ ๋ฐฉ๋ฒ์ [weak self]๋ฅผ ์ฌ์ฉํ์ง ์๊ณ ๋์ค์ ์ฌ์ฉํ ์ ์๋๋ก ์ ๋๋ฉ์ด์
์ ์ ์ฅํ๊ธฐ ๋๋ฌธ์ ์ํ์ฐธ์กฐ๋ฅผ ์ ๋ฐํ๋ค.
func setupAnimation() {
let anim = UIViewPropertyAnimator(duration: 2.0,
curve: .linear) {
self.view.backgroundColor = .red
}
anim.addCompletion { _ in
self.view.backgroundColor = .white
}
self.animationStorage = anim
}
[Storing a function in a property]
ํ ๊ฐ์ฒด์ ํด๋ก์ ๋ ํจ์๋ฅผ ๋ค๋ฅธ ๊ฐ์ฒด์ ์ ๋ฌํ์ฌ ์์ฑ์ ์ ์ฅํ๋ ์ํฉ์ ๋์ ๋์ง ์๋ ๋ฉ๋ชจ๋ฆฌ ๋์๋ฅผ ์ ๋ฐํ ์ ์๋ค.
์๋ฅผ ๋ค์ด, ์์ฑ(property)์ ํด๋ก์ ๋ฅผ ์ ์ฅํ๋ PresentedController๊ฐ ์๋ค.
class PresentedController: UIViewController {
var closure: (() -> Void)?
}
๊ทธ๋ฆฌ๊ณ PresentedController๋ฅผ ๊ฐ์ง๊ณ ์๋ MainViewController๊ฐ ์๊ณ ,
MainViewController์ printer() ๋ฉ์๋๋ฅผ PresentedController์ ํด๋ก์ ์ ์ ์ฅํ๋ค.
class MainViewController: UIViewController {
var presented = PresentedController()
func setupClosure() {
// ํจ์ ์์ฒด๋ฅผ ํ ๋นํ๊ธฐ ๋๋ฌธ์ ()๊ดํธ๋ฅผ ํฌํจํ์ง ์์.
presented.closure = printer
}
func printer() {
print(self.view.description)
}
}
์ด์ PresentedController์์ ํด๋ก์ ๋ฅผ ํธ์ถํ๋ฉด MainViewController์ self.view.description๋ฅผ ํ๋ฆฐํธํ ์ ์๋ค.
ํ์ง๋ง ์ด ์ฝ๋๋ ๋ช ์์ ์ผ๋ก self๋ฅผ ์ฌ์ฉํ์ง ์์์์๋ ์ํ์ฐธ์กฐ๋ฅผ ์ ๋ฐํ๋ค.
self๋ printer์ ์์๋์ด ์๋ค.(printer == self.priner)
๋ฐ๋ผ์ ํด๋ก์ ๋ self.printer์ ๋ํ ๊ฐ๋ ฅํ ์ฐธ์กฐ๋ฅผ ์ ์งํ๋ ๋ฐ๋ฉด self๋ ํด๋ก์ ๋ฅผ ์์ ํ๋ PresentedController๋ฅผ ์์ ํ๋ค.
๋๋ฌธ์ ์ํ์ฐธ์กฐ๋ฅผ ์ ๊ฑฐํ๊ธฐ ์ํด [weak self]๋ฅผ ํฌํจํ๋๋ก setupClosure๋ฅผ ์์ ํด์ผ ํ๋ค.
func setupClosure() {
presented.closure = { [weak self] in
// ๋ฒ์(scope) ๋ด์์ ํด๋น ํจ์๋ฅผ ํธ์ถํ๊ธฐ๋ฅผ ์ํ๊ธฐ ๋๋ฌธ์
// ์ด๋ฒ์๋ ํ๋ฆฐํฐ ๋ค์์ ()๊ดํธ๋ฅผ ํฌํจ.
self?.printer()
}
}
[Timer]
Timer๋ ์์ฑ(property)์ ์ ์ฅํ์ง ์๋๋ผ๋ ๋ฌธ์ ๋ฅผ ์ผ์ผํฌ ์ ์๋ค.
-
Timer๊ฐ ๋ฐ๋ณต๋๋ค.
-
[weak self]๋ฅผ ์ฌ์ฉํ์ง ์๊ณ ํด๋ก์ ์์ self๋ฅผ ์ฐธ์กฐํ๋ค.
์ด ๋ ์กฐ๊ฑด์ด ์ถฉ์กฑ๋๋ ํ ํ์ด๋จธ๋ ์ฐธ์กฐ๋ ์ปจํธ๋กค๋ฌ ๋๋ ๊ฐ์ฒด์ ํ ๋น ํด์ ๋ฅผ ๋ฐฉ์งํฉ๋๋ค.
๋ฐ๋ผ์ ๊ธฐ์ ์ ์ผ๋ก ๋ฉ๋ชจ๋ฆฌ ๋์๋ณด๋ค๋ Delayed Deallocation์ ๊ฐ๊น๋ค.
Delayed Deallocation๋ ๋ฌดํ์ ์ง์๋๋ค.
์ฐธ์กฐ๋ ๊ฐ์ฒด๋ฅผ ๋ฌด๊ธฐํ ํ์ฑ ์ํ๋ก ์ ์งํ๋ ๊ฒ์ ํผํ๊ธฐ ์ํด
๋ ์ด์ ํ์ํ์ง ์์ ๋ ํ์ด๋จธ๋ฅผ ๋ฌดํจํํ๊ณ ์ฐธ์กฐ๋ ๊ฐ์ฒด๊ฐ ํ์ด๋จธ์ ๋ํ ๊ฐํ ์ฐธ์กฐ๋ฅผ ์ ์งํ๋ ๊ฒฝ์ฐ [weak self]๋ฅผ ์ฌ์ฉํด์ผ ํ๋ค.
์๋ฃ ์ถ์ฒ
https://velog.io/@haanwave/Article-You-dont-always-need-weak-self