Swift 메모리 관리 마스터하기: weak와 unowned 참조를 사용한 메모리 관리 전략.

작성일 :

Swift 메모리 관리 마스터하기: weak와 unowned 참조를 사용한 메모리 관리 전략

Swift에서는 자동 참조 카운팅(Automatic Reference Counting, ARC)을 사용하여 메모리를 관리합니다. ARC는 객체의 생명 주기를 추적하고 필요 없을 때 자동으로 메모리를 해제합니다. 하지만 ARC가 모든 메모리 문제를 다 해결하지는 못합니다. 강한 참조 순환(strong reference cycle) 같은 문제는 여전히 수동으로 해결해야 합니다. 이 글에서는 weakunowned 참조를 사용해 이러한 문제를 어떻게 해결할 수 있는지 알아보겠습니다.

자동 참조 카운팅(ARC)

ARC는 각 객체가 얼마나 많은 참조를 받고 있는지 추적합니다. 객체에 대한 참조가 추가될 때마다 참조 카운트가 증가하고, 참조가 삭제될 때마다 감소합니다. 참조 카운트가 0이 되는 순간, 객체는 메모리에서 해제됩니다.

그러나 두 객체가 서로를 강하게(강한 참조) 참조하면 참조 카운트가 0이 되지 않아 메모리 누수가 발생할 수 있습니다. 이를 해결하기 위해 weakunowned 참조가 등장합니다.

weak 참조

weak 참조는 강한 참조 순환 문제를 해결하는 주요 도구 중 하나입니다. weak 참조는 참조하는 객체가 메모리에서 해제되더라도 참조를 유지하지 않습니다. 그렇기 때문에 참조 카운트를 증가시키지 않습니다. 이런 weak 참조는 종종 순환 참조를 피하기 위해 사용됩니다.

swift
class Person {
    let name: String
    init(name: String) { self.name = name }
    var apartment: Apartment?
}

class Apartment {
    let unit: String
    init(unit: String) { self.unit = unit }
    weak var tenant: Person?
}

var john: Person? = Person(name: "John Appleseed")
var unit4A: Apartment? = Apartment(unit: "4A")

john!.apartment = unit4A
unit4A!.tenant = john

이 예제에서는 Person 객체와 Apartment 객체가 서로를 참조하고 있음을 볼 수 있습니다. Apartment 클래스의 tenant 속성이 weak으로 선언되었기 때문에, Person 객체는 참조 카운터를 증가시키지 않고 메모리에서 해제될 수 있습니다.

weak 참조의 특징

  • nil로 설정될 수 있다.
  • 메모리가 해제되면 자동으로 nil이 된다.
  • 참조 카운트를 증가시키지 않는다.

unowned 참조

unowned 참조는 또 다른 강력한 도구로, 참조하는 객체가 해제되더라도 참조를 유지하지 않습니다. 그러나 이 참조는 메모리가 해제되더라도 자동으로 nil이 되지 않으므로, 해제된 참조를 접근하려 하면 런타임 에러가 발생합니다. unowned 참조는 참조가 항상 유효하다고 판단되는 경우에 사용됩니다.

swift
class Customer {
    let name: String
    var card: CreditCard?
    init(name: String) {
        self.name = name
    }
}

class CreditCard {
    let number: UInt64
    unowned let customer: Customer
    init(number: UInt64, customer: Customer) {
        self.number = number
        self.customer = customer
    }
}

var john: Customer? = Customer(name: "John Appleseed")
john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)

위 예제에서 CreditCard 클래스는 unowned 참조를 사용하여 Customer 객체를 참조합니다. 이는 Customer 객체가 항상 CreditCard 객체보다 오래 살아남음을 보장하기 때문에 안전합니다.

unowned 참조의 특징

  • nil로 설정될 수 없다.
  • 메모리가 해제되더라도 참조를 유지하지만, 접근 시 크래시가 발생할 수 있다.
  • 참조 카운트를 증가시키지 않는다.

언제 weak와 unowned 참조를 사용해야 할까?

  • weak 참조는 상대 객체가 해제될 수 있으며, 이를 안전하게 처리하기 원할 때 사용합니다. 주로 부모-자식 관계에서 자식이 부모를 약하게 참조하도록 설정합니다.
  • unowned 참조는 상대 객체의 생명 주기가 참조하는 객체보다 길거나 같음을 확신할 수 있을 때 사용합니다. unowned 참조는 일반적으로 약한 참조보다 성능이 좋습니다.

결론

ARC는 Swift의 메모리 관리를 자동화하여 개발자가 메모리 누수나 해제 문제에 신경 쓰지 않도록 돕습니다. 그러나 강한 참조 순환 문제는 여전히 개발자가 수동으로 해결해야 합니다. 이 글에서는 weakunowned 참조를 사용하여 이러한 문제를 어떻게 해결할 수 있는지 설명했습니다. weak 참조는 nil을 허용하며 메모리 해제 후 자동으로 nil이 되는 것을 보장합니다. 반면에 unowned 참조는 nil을 허용하지 않으며 참조 객체가 항상 유효할 것으로 가정됩니다. 이 두 가지 도구를 적절히 사용하면 메모리 관리를 더욱 효과적으로 할 수 있습니다.