학습
Swift 메모리 관리 및 최적화
Swift 메모리 관리 및 최적화 — 고급
메모리 관리 및 최적화
1. 도입 (왜 배워야 하는가)
Swift에서는 메모리 관리를 올바르게 이해하고 활용하는 것이 매우 중요합니다. 메모리 관리는 앱의 성능과 안정성에 직접적인 영향을 미치며, 잘못된 메모리 관리로 인해 앱이 느려지거나 크래시가 발생할 수 있습니다. 특히, 애플리케이션이 복잡해질수록 메모리 사용을 최적화하는 것이 필수적입니다.
메모리 관련 문제는 종종 사용자 경험에 큰 영향을 미치며, 개발자는 이를 예방하기 위해 메모리 관리 기법을 숙지해야 합니다. 예를 들어, 메모리 누수는 앱이 충분한 메모리를 확보하지 못하게 하여 성능 저하를 초래할 수 있습니다. 따라서 메모리 관리 및 최적화는 개발자가 반드시 숙지해야 할 필수 역량입니다.
2. 핵심 개념 설명
2.1. ARC (Automatic Reference Counting)
ARC는 Swift에서 메모리를 자동으로 관리하는 시스템입니다. 객체의 참조 수를 통해 메모리 할당과 해제를 자동으로 수행합니다. 마치 가정에서 쓰레기를 정기적으로 수거하는 서비스와 같다고 비유할 수 있습니다. 쓰레기가 쌓이지 않도록 관리해 주는 것과 같이, ARC는 객체가 더 이상 필요하지 않을 때 메모리를 해제해 줍니다.
2.2. Strong Reference, Weak Reference, Unowned Reference
- Strong Reference: 객체의 참조 수를 증가시키며, 객체가 해제되지 않도록 유지합니다.
- Weak Reference: 객체의 참조 수를 증가시키지 않으며, 객체가 해제될 수 있도록 합니다. 주로 순환 참조 문제를 방지하는 데 사용됩니다.
- Unowned Reference: 객체의 강한 참조를 가지지 않지만, 객체가 항상 존재한다고 가정하는 참조입니다.
| 용어 | 설명 | 사용 예 |
|---|---|---|
| Strong Reference | 객체를 소유하는 참조 | 일반적인 객체 참조 |
| Weak Reference | 객체를 소유하지 않는 참조 | 순환 참조 방지 |
| Unowned Reference | 객체의 소유가 없지만 항상 존재하는 참조 | 클로저에서 self 참조 |
3. 기본 코드 예제
아래 예제는 ARC의 기본적인 동작을 보여줍니다.
class Person {
var name: String
init(name: String) {
self.name = name
print("\(name) 생성")
}
deinit {
print("\(name) 해제")
}
}
var john: Person? = Person(name: "존")
john = nil // 존 객체가 메모리에서 해제됨
실행 결과
존 생성
존 해제
class Person: Person 객체를 정의합니다.init(name:): 객체가 생성될 때 호출되는 초기화 메서드입니다.deinit: 객체가 메모리에서 해제될 때 호출되는 메서드입니다.var john: Person?: 옵셔널 타입으로 Person 객체를 생성하고, john 변수에 할당합니다.john = nil: john을 nil로 설정하여 메모리에서 해제합니다.4. 실전 활용 예제
4.1. 장바구니 구현
쇼핑몰에서 장바구니를 구현할 때, 제품 객체와 장바구니 객체 간의 관계를 정의할 수 있습니다.
class Product {
var name: String
init(name: String) {
self.name = name
}
}
class ShoppingCart {
var products: [Product] = []
func addProduct(_ product: Product) {
products.append(product)
}
}
var cart = ShoppingCart()
let apple = Product(name: "사과")
cart.addProduct(apple)
4.2. 순환 참조 방지
순환 참조를 방지하기 위해 weak 참조를 사용합니다.
class Customer {
var name: String
var order: Order?
init(name: String) {
self.name = name
}
}
class Order {
var customer: Customer?
init(customer: Customer) {
self.customer = customer
}
}
여기서 Order 클래스에서 Customer 객체를 weak로 참조하게 되면 메모리 누수를 방지할 수 있습니다.
5. 흔한 실수와 주의사항
실수 1: 순환 참조
class A {
var b: B?
}
class B {
var a: A?
}
// 잘못된 코드: 순환 참조가 발생하여 메모리 누수
let a = A()
let b = B()
a.b = b
b.a = a
올바른 코드:
class A {
var b: B?
}
class B {
weak var a: A? // weak로 참조하여 순환 참조 방지
}
실수 2: 강한 참조를 사용해야 할 때
class SomeClass {
var property: SomeOtherClass?
}
// 잘못된 코드: property가 nil일 수 있어 문제가 발생할 수 있음
올바른 코드:
class SomeClass {
var property: SomeOtherClass! // 강한 참조를 보장
}