Swift에서 프로퍼티 Assign 개념 이해하기: Reference Type과 ARC

작성일 :

Swift에서 프로퍼티 Assign 개념 이해하기: Reference Type과 ARC

Swift에서 프로퍼티를 이해하고 적절히 사용하는 것은 매우 중요합니다. 특히, Reference Type과 Automatic Reference Counting(ARC)을 제대로 이해하면 메모리 관리 및 성능 최적화에 큰 도움이 됩니다. 이번 글에서는 Swift의 프로퍼티 Assign 개념을 중심으로 Reference Type과 ARC에 대해 자세히 살펴보겠습니다.

프로퍼티의 Assign 개념

Swift에서 프로퍼티는 클래스, 구조체, 열거형 내부에서 값을 저장하는 변수나 상수를 의미합니다. 프로퍼티에는 크게 두 가지 유형이 있습니다: Stored PropertyComputed Property입니다.

  • Stored Property: 이는 값을 저장하는 프로퍼티로, 변수(var)나 상수(let)로 선언할 수 있습니다.
  • Computed Property: 이는 실질적인 값이 저장되지 않고, getter와 setter를 통해 값을 연산하는 프로퍼티입니다.

프로퍼티를 선언하고 나면, 다양한 방식으로 해당 프로퍼티에 값을 할당(assign)할 수 있습니다. 구조체와 열거형은 값 타입(Value Type)이고, 클래스는 참조 타입(Reference Type)입니다.

Reference Type과 값 타입

Swift에서는 변수나 상수에 값을 할당할 때, 값 타입과 참조 타입 두 가지 방식이 있습니다. 이는 프로퍼티의 동작 방식을 결정하는 중요한 요소입니다.

  • 값 타입(Value Type): 변수나 상수가 직접 값을 저장합니다. 구조체와 열거형이 값 타입입니다. 값을 할당하거나 함수에 전달할 때, 복사본이 전달됩니다.
  • 참조 타입(Reference Type): 변수나 상수가 값이 저장된 메모리 주소를 참조합니다. 클래스가 참조 타입입니다. 값을 할당하거나 함수에 전달할 때, 같은 메모리 주소를 참조하므로 원본 값이 변경될 수 있습니다.

예를 들어, 구조체와 클래스를 이용한 간단한 예제를 살펴보겠습니다.

swift
struct ValueTypeExample {
    var value: Int
}

class ReferenceTypeExample {
    var value: Int
    init(value: Int) {
        self.value = value
    }
}

var aStruct = ValueTypeExample(value: 10)
var anotherStruct = aStruct
anotherStruct.value = 20
print(aStruct.value) // 10
print(anotherStruct.value) // 20

var aClass = ReferenceTypeExample(value: 10)
var anotherClass = aClass
anotherClass.value = 20
print(aClass.value) // 20
print(anotherClass.value) // 20

위 예제에서 구조체인 ValueTypeExample은 값 타입이므로 anotherStruct에 할당될 때 값이 복사됩니다. 반면, 클래스인 ReferenceTypeExample은 참조 타입이므로 anotherClass에 할당될 때 동일한 값(메모리 주소)을 참조하게 됩니다. 따라서 하나의 변수에서 값을 변경하면 다른 변수에서도 그 변경이 반영됩니다.

Automatic Reference Counting (ARC)

참조 타입을 사용할 때 중요한 개념 중 하나가 ARC입니다. ARC는 Automatic Reference Counting의 줄임말로, Swift에서 메모리 관리를 자동으로 처리해주는 기능입니다. ARC는 클래스 인스턴스를 생성하고 더 이상 필요하지 않게 될 때 메모리를 자동으로 해제합니다.

ARC는 각 클래스 인스턴스의 참조 횟수(reference count)를 추적하여, 더 이상 참조되지 않는 인스턴스를 메모리에서 자동으로 제거합니다. 이를 통해 프로그래머가 직접 메모리 관리를 하지 않아도 됩니다. 그러나 ARC를 제대로 이해하고 사용하지 않으면 강한 참조 순환(strong reference cycle) 문제가 발생할 수 있습니다.

강한 참조 순환 문제는 서로 간에 강한 참조를 하여 참조 횟수가 0이 되지 않아 메모리에서 해제되지 않는 문제입니다. 이 문제를 해결하기 위해서는 weak 또는 unowned 키워드를 사용할 수 있습니다.

강한 참조 순환 해결 방법

  1. weak: 참조가 약한 참조임을 나타내며, 참조된 인스턴스가 메모리에서 해제되면 참조는 자동으로 nil로 설정됩니다. 주로 optional 타입과 함께 사용합니다.
swift
class Person {
    var name: String
    weak var friend: Person?
    init(name: String) {
        self.name = name
    }
}
  1. unowned: 참조가 강한 참조가 아니며, 참조된 인스턴스가 메모리에서 해제되면 접근할 수 없습니다. non-optional 필드에서 사용해야 하며, 참조된 인스턴스가 해제되었는지 가정합니다.
swift
class Person {
    var name: String
    unowned var friend: Person
    init(name: String, friend: Person) {
        self.name = name
        self.friend = friend
    }
}

예제 코드

다음은 강한 참조 순환을 해결하기 위해 weak 키워드를 사용한 예제 코드입니다:

swift
class Owner {
    var name: String
    var gadget: Gadget?
    init(name: String) {
        self.name = name
    }
    deinit {
        print("\