TIL
🌱 난 오늘 무엇을 공부했을까?
📍 Allocation
- 스택 할당은 매우 빠름.
- 힙은 동적이지만 덜 효율적(O(log n)).
- 또한 오버헤드가 많은 스레드 안전성을 확인하여 무결성을 보호해야 함.
struct Point {
var x, y: Double
func draw() { ... }
}
let point1 = Point(x: 0, y: 0)
var point2 = point1
point2.x = 5
- 구조체 point1과 point2는 값타입이고 복사하기 때문에 서로 다름.
class Point {
var x, y: Double
func draw() { ... }
}
let point1 = Point(x: 0, y: 0)
var point2 = point1
point2.x = 5
- 클래스로 만들면 참조 타입이라 복사를 하지 않기 때문에 값이 같다.
enum Color {
case blue, green, gray
}
enum Orientation {
case left, right
}
enum Tail {
case none, tail, bubble
}
var cache = [String: UIImage]()
func makeBalloon(_ color: Color, orientation: Orientation, tail: Tail) -> UIImage {
let key = “\(color):\(orientation):\(tail)”
if let image = cache[key] {
return image
}
}
- 문자열은 표현할 수 있는 값의 측면에서 거의 무한함. 그렇기 때문에 강력한 키가 아님.
- 문자열은 문자의 내용을 힙에 간접적으로 저장. 캐시 히트가 발생하더라도 키를 구성할 때 여전히 힙 할당이 발생.
- 키를 3가지 속성의 구조체로 나타내기. 이것은 일급 유형이며 사전에서 키로 사용이 가능하다.
- 훨씬 안전하고 빠릅니다.
enum Color {
case blue, green, gray
}
enum Orientation {
case left, right
}
enum Tail {
case none, tail, bubble
}
struct Attributes: Hashable {
var color: Color
var orientation: Orientation
var tail: Tail
}
var cache = [Attribute: UIImage]()
func makeBalloon(_ color: Color, orientation: Orientation, tail: Tail) -> UIImage {
let key = Attributes(color: color, orientation: orientation, tail: tail)
if let image = cache[key] {
return image
}
}
📍 ARC
- 언제 힙에서 인스턴스를 할당 해제하는 것이 안전한지 알기 위해 Swift는 참조 카운팅을 사용. 아무도 가리키지 않으면 Swift가 할당을 해제.
- 간접 및 스레드 안전성 검사가 많이 있고 이를 원자적으로 수행해야 하기 때문에 비용이 추가되기 때문에 ARC는 단순히 증가/감소하는 것보다 비용이 많이 든다.
class Point {
var refCount: Int
var x, y: Double
func draw() { ... }
}
let point1 = Point(x: 0, y: 0)
var point2 = point1
retain(point2)
point2.x = 5
release(point1)
release(point2)
- 구조체는 참조 계산 오버헤드가 없지만, 더 복잡한 구조체를 고려해 보자.
struct Label {
var text: String
var font: UIFont
func draw() { ... }
}
let label1 = Label(text: "hi", font: font)
let label2 = label1
struct Label {
var text: String
var font: UIFont
func draw() { ... }
}
let label1 = Label(text: "hi", font: font)
let label2 = label1
retain(label2.text._storage)
retain(label2.font)
release(label1.text._storage)
release(label1.font)
release(label2.text._storage)
release(label2.font)
- 구조체는 프로퍼티로 0 또는 1개의 참조 유형이 있는 경우에만 ARC 측면에서 유리ㅈ함.
- 이를 위해
uuid: String
대신 Foundation의 내장 UUID 유형을 사용하십시오.
- 문자열 대신 열거형을 사용.
📍 Method Dispatch
- Swift가 컴파일 시간에 실행할 메소드를 말할 수 있다면 이를 정적 디스패치라고 하며 런타임에 해당 코드로 바로 이동할 수 있습니다.
- 컴파일러는 인라인(호출이 있는 위치에 함수 본문을 문자 그대로 복사하여 붙여넣기) 또는 기타 트릭을 통해 주변 코드에 적극적으로 최적화할 수도 있습니다.
- 이것은 새로운 스택 프레임 등을 피하는 데 도움이 됩니다.
- 정적 디스패치 체인을 실제로 원하는 코드로 축소할 수 있습니다.
- 그렇지 않으면 코드에 도달하기 전에 호출할 메서드를 파악하는 오버헤드가 있는 동적 디스패치를 사용하고 주요 단점인 컴파일러 최적화를 포기합니다.
- 상속 기반 다형성은 코드에서 더 많은 유연성을 제공하지만 정적 디스패칭을 포기.
참고