[220905] TIL
Opened this issue · 2 comments
Taehyeon-Kim commented
ARC
메모리 구조
- 코드 : 우리가 작성하는 코드가 들어가는 영역
- 데이터 : 전역적으로 쓰일 수 있는 변수 (타입 프로퍼티)
- 힙 : ARC가 관리하는 영역, 클래스의 경우 인스턴스를 생성(인스턴스를 생성, 제거할 때마다 메모리에 올렸다가 내렸다가 하는 과정 필요)
- 스택
ARC
- Auto Reference Counting
RC (참조 횟수)
- Reference Count
- 인스턴스 생성 -> 메모리에 올라갔다. -> RC+1
- 인스턴스 해제 -> 메모리에서 내려갔다. -> RC-1
- RC == 0 인 시점에 힙영역에서 내린다. (=메모리 해제)
생성/해제
var user: User? = User(name: "고래밥") // User: RC 1
var guild: Guild? = Guild(name: "SeSAC") // Guild: RC 1
guild = nil // Guild: RC 0
user = nil // User: RC 0
/*
User init
Guild init
Guild deinit
User deinit
*/
var user: User? = User(name: "고래밥") // User: RC 1
var guild: Guild? = Guild(name: "SeSAC") // Guild: RC 1
user?.guild = guild // Guild: RC 2
guild?.owner = user // User: RC 2
guild = nil // Guild: RC 1
user = nil // User: RC 1
/*
User init
Guild init
*/
// ==> 순환 참조 발생
해결
순환 참조인 녀석을 먼저 nil
var user: User? = User(name: "고래밥") // User: RC 1
var guild: Guild? = Guild(name: "SeSAC") // Guild: RC 1
user?.guild = guild // Guild: RC 2
guild?.owner = user // User: RC 2
guild?.owner = nil // User: RC 1
guild = nil // Guild: RC 1
user = nil // User: RC 0 -> user deinit -> Guild: RC 0
/*
User init
Guild init
User deinit
Guild deinit
*/
수동으로 해결하기 어렵다.
- 관계 다 찾아서 해결할 수 있겠니?
- 아뇨
- 그래서 쉽게 해결할 수 있는 방법을 준비했단다.
weak, unowned keyword
- weak : RC를 증가시키지 않는다.
- ex. IBOutlet 부분
- 수명(RC로 파악)이 더 짧은 인스턴스를 가리키는 녀석을 약한 참조(weak)로 선언하자
- unowned : RC를 증가시키지 않는다.
ARC + delegate
- delegate를 사용할때는 weak를 필수적으로 써주어야 함.
- 뷰 컨트롤러가 생성되고 해제되는 문제를 해결해주어야 함.
- weak 키워드를 경우에는 결국 class에서 사용을 제한해주어야 하기 때문에 AnyObject로 제약을 걸어주어야 함.
protocol MyDelegate: AnyObject {
func sendData(_ data: String)
}
protocol BDelegate: AnyObject {
func method()
}
class A: BDelegate {
lazy var b: B = {
let view = B()
view.delegate = self
return view
}()
func method() {
// code
}
}
class B {
weak var delegate: BDelegate?
func dismiss() {
delegate?.method()
}
}
// var A: A? = A()
// A?.b
// A.nil
/*
weak키워드로 참조를 약하게 만들지 않으면 A, B의 인스턴스는 해제되지 않는다.
*/
ARC + Closure
import UIKit
class User {
var nickname = "JACK"
lazy var introduce: () -> String = { [weak self] in
return "저는 \(String(describing: self?.nickname))입니다." // self로 접근하기 때문에 순환 참조 발생
}
init() {
print("User init")
}
deinit {
print("User deinit")
}
}
var user: User? = User()
user?.introduce() // RC + 1
user = nil
// User init
// User deinit
값 캡처
- 호출시에 값이 캡처된다.
func myClosure() {
var number = 0
print("1: \(number)")
let closure: () -> Void = { [number] in // 값 캡처, 값 타입 - 복사, 클로저 안에서는 값이 영향을 받지 않는다.
print("closure: \(number)")
}
closure()
number = 100
print("2: \(number)")
closure()
}
myClosure()
/*
1: 0
closure: 0
2: 100
closure: 0
*/
Taehyeon-Kim commented
Swift에서 메모리를 어떻게 하죠?
- MRC -> ARC
- 참조에 대한 차이로 strong, weak, unowned가 존재한다.
weak와 unowned의 차이는 무엇인가?
Taehyeon-Kim commented
메모리에서 인스턴스가 해제되었는지 어떻게 아나요?
- deinit으로 확인해본다.