
Contents
ARC순환참조 찾는 방법autoReleasepoolValue Type | Refernece Type왜 value type이 Reference type보다 빠를까?Dynamic | Static DispatchDispatchclass 내 Dispatchstruct 내 Dispatch protocol 내 DispatchSwift의 Protocol은 어떻게 적용될까?Protocol 배열Existentical ContainerProtocol Argument 함수Swift의 Genericprotocol을 곁들인1️⃣ - 프로토콜 인자로 받음2️⃣ - Generic 인자로 받음ARC
Automatic Reference Count
- 컴파일 타임에 동작
Strong
,weak
는 ARC테이블을 통해 간접참조
unowned
은 ARC테이블을 사용하지 않고 직접 참조한다.
순환참조 찾는 방법
- Instrument - Leak
- Graph
- CFRetainCount로 디버깅
- 메모리 증감 살피기
autoReleasepool
- 해당 블록 내에서는 ARC 증감 내역을블록 종류 후에 반영한다.
Value Type | Refernece Type
왜 value type이 Reference type보다 빠를까?
- Heap 메모리 선언시 오버헤드가 크기 때문이다.
- Heap 메모리 저장하기 위한 Heap 메모리 탐색
- Heap 저장한 메모리를 멀티 스레드에 sync 맞추기
- 해제 과정도 멀티 스레드에 반영해야 함
Dynamic | Static Dispatch
Dispatch
- 사전 뜻: 발송 → 어떤 함수를 실행 시킬 것인지 결정하는 것
class 내 Dispatch
- 기본적으로 dynamic
- private / final 키워드가 붙으면 static
- private → 상속이 불가능
- final → 상속이 불가능
- extension 내 함수 → static
- 상속 및 override 불가능 → Static
struct 내 Dispatch
- static
protocol 내 Dispatch
- 기본적으로 dynamic
protocol 선언 O / extension 구현 O / 객체 구현 O
→ Dynamic
- 객체에 구현된 것이 우선적으로 적용됨으로 Dynamic
protocol 선언 O / extension 구현 O / 객체 구현 X
- Static
- extension에 구현되었고 상속이 불가능 함으로 Static
protocol 선언 X / extension 구현 O / 객체 구현 O
- 상황에 따라 다르다.
- protocol type의 객체 → Static (extension 사용)
- protocol 상속받은 type → Dynamic (객체 사용)
protocol A { }
extension A {
func testFunc() {
print("It's protocol")
}
}
class B: A {
func testFunc() {
print("It's Object")
}
}
let obj1: B = B()
let obj2: A = B()
obj1: B
은 Dynamic obj2: A
는 Static으로 작동한다.Swift의 Protocol은 어떻게 적용될까?
Protocol 배열
- Protocol을 따르는 객체의 크기는 모두다 다른데 어떻게 메모리에 저장될까?
→
Existentical Container
활용Existentical Container

- Existentical Container는 위와 같이 구성됨
Value Buffer
- Value Buffer에 실질적으로 Protocol을 따르는 객체의 메모리가 올라가게 됨
- 객체의 크기가 3word 이상이다? → 객체는 Heap에 저장되고 Value Buffer에는 주소 값을 갖게 됨
Value Witness Table
- 객체의 allocate deallocate copy destruct 를 맡음
Ptorocol Witness Table
- protocl 함수 구현부 위치를 갖고 있는 테이블
Protocol Argument 함수
Protocol을 따르는 함수인자를 받을 때 어떻게 적용되나?
→ Existentical Container로 넘긴다.
→ 그럼 그게 class랑 뭐가 달라?
→ COW를 활용하여 최대한 heap을 덜 사용한다.
Swift의 Generic
protocol을 곁들인
// 1️⃣
struct A {
init(a: Drawable, b: Drawable)
}
// 2️⃣
struct A<T: Drawable> {
init(a: T, b: T)
}
이 2개는 어떻게 다를까?
1️⃣ - 프로토콜 인자로 받음
이 경우 Extential Container로 Protocol객체를 받는다. value Buffer가 클 경우에 heap이 사용된다.
2️⃣ - Generic 인자로 받음
Swift Complier에서 해당 Generic을 사용해 만들 수 있는 모든 생성자를 만듬
protocol Pro { }
class A: Pro { }
struct B: Pro { }
struct C<T: Pro> {
init(a: T, b: T)
}
위 예시인 경우 Swift Complier가 아래와 같이 생성자를 만든다.
struct C<T: Pro> {
init(a: A, b: A)
init(a: B, b: B)
}
위와 같이 생성자를 직접 만듬으로 컴파일 시간에서 빌드되게 만들어준다.
→ 그럼 코드가 너무 많이 늘어나느거 아님?
사실상 최적화 때문에 사실상 오히려 코드가 줄어든다고 한다.
Share article