프로그래밍공부(Programming Study)/IOS 개발

Swift에서 클래스의 강한 참조, 약한 참조, unowned 참조 완벽 가이드

Chann._.y 2024. 11. 10.
728x90

1. 강한 참조(Strong Reference)란?

Swift에서 강한 참조(Strong Reference)는 객체의 소유권을 유지하는 참조 방식입니다. 기본적으로 모든 참조는 강한 참조로 설정되며, 객체가 다른 객체를 강한 참조하면 참조 카운트가 증가하여 그 객체가 메모리에서 해제되지 않도록 보장됩니다.

특징

  • 기본 참조 방식으로, 객체의 소유권을 유지합니다.
  • 객체를 참조하는 동안 메모리에서 해제되지 않습니다.
  • 순환 참조를 발생시킬 수 있으므로, 상호 참조가 필요한 경우 주의해야 합니다.

사용 예시

강한 참조는 대부분의 상황에서 사용되며, 객체가 독립적으로 존재할 때 적합합니다.

class Person {
    var name: String
    var pet: Pet? // 기본적으로 강한 참조

    init(name: String) {
        self.name = name
    }
}

class Pet {
    var type: String
    var owner: Person? // 기본적으로 강한 참조

    init(type: String) {
        self.type = type
    }
}

let john = Person(name: "John")
let cat = Pet(type: "Cat")

john.pet = cat
cat.owner = john

설명

위 코드에서는 Person 객체 johnPet 객체 cat이 서로를 강한 참조합니다. 이 경우, johncat이 서로를 참조하고 있기 때문에, 순환 참조(Circular Reference)가 발생할 수 있습니다. 이로 인해 johncat은 서로를 참조한 채 메모리에서 해제되지 않습니다. 이를 해결하려면 약한 참조 또는 unowned 참조를 사용해야 합니다.


2. 약한 참조(Weak Reference)란?

약한 참조(Weak Reference)객체의 소유권을 유지하지 않는 참조 방식입니다. 약한 참조는 객체가 더 이상 사용되지 않을 때 메모리에서 해제될 수 있도록 하며, 순환 참조를 방지하는 데 주로 사용됩니다. 약한 참조는 항상 옵셔널(Optional) 타입으로 선언되어야 하며, 객체가 해제되면 자동으로 nil로 설정됩니다.

특징

  • 객체의 소유권을 유지하지 않고, 객체가 해제되면 자동으로 nil로 설정됩니다.
  • 약한 참조는 항상 옵셔널 타입으로 선언되어야 합니다.
  • 순환 참조를 방지할 때 주로 사용됩니다.

사용 예시

약한 참조는 보통 상호 참조를 방지하기 위해 한쪽의 참조를 약한 참조로 설정합니다.

class Person {
    var name: String
    var pet: Pet? // 강한 참조

    init(name: String) {
        self.name = name
    }
}

class Pet {
    var type: String
    weak var owner: Person? // 약한 참조

    init(type: String) {
        self.type = type
    }
}

let john = Person(name: "John")
let cat = Pet(type: "Cat")

john.pet = cat
cat.owner = john // 약한 참조이므로 순환 참조 방지

설명

위 코드에서 owner 속성은 weak 키워드를 사용하여 약한 참조로 선언되었습니다. 따라서 Person 인스턴스가 메모리에서 해제되면 Pet 인스턴스의 owner 속성은 자동으로 nil로 설정됩니다. 이로써 순환 참조 없이 두 객체가 서로 참조할 수 있습니다.


3. Unowned 참조란?

Unowned 참조는 약한 참조와 비슷하게 객체의 소유권을 유지하지 않으면서 참조하는 방식입니다. 하지만 약한 참조와 다르게 Optional이 아니며, 참조가 항상 메모리에 존재한다고 확신할 때 사용합니다. 객체가 해제된 후에 unowned 참조에 접근하면 런타임 오류가 발생하므로, 수명이 보장된 경우에만 사용해야 합니다.

특징

  • nil을 허용하지 않는 비옵셔널 참조입니다.
  • 객체의 소유권을 유지하지 않으므로, 메모리 해제에 영향을 미치지 않습니다.
  • 참조 대상보다 수명이 짧거나 종속적인 객체에 적합합니다.

사용 예시

unowned 참조는 보통 참조 대상이 항상 유효할 것으로 확신할 때 사용합니다.

class Company {
    var name: String
    var ceo: Employee?

    init(name: String) {
        self.name = name
    }
}

class Employee {
    var name: String
    unowned var company: Company // unowned 참조

    init(name: String, company: Company) {
        self.name = name
        self.company = company
    }
}

let apple = Company(name: "Apple")
let tim = Employee(name: "Tim", company: apple)
apple.ceo = tim

설명

위 코드에서 Employeecompany 속성은 unowned 참조로 선언되었습니다. 이 설정으로 EmployeeCompany 객체가 해제될 때까지 company 속성을 참조할 수 있습니다. Employee는 항상 Company와 함께 해제되므로 순환 참조의 위험 없이 안전하게 참조할 수 있습니다.


4. 참조 타입의 사용 시기와 사례

Swift에서는 메모리 관리와 객체 간의 관계를 명확히 하기 위해 참조 타입을 상황에 맞게 사용합니다.

참조 타입 사용 시기 및 사례
강한 참조 기본적인 참조 방식으로, 객체 간의 단방향 참조에 적합합니다. 순환 참조가 발생하지 않을 때 대부분 강한 참조를 사용합니다.
약한 참조 순환 참조가 발생할 수 있는 경우에 사용합니다. 예를 들어, 부모-자식 관계에서 자식이 부모를 약한 참조로 설정하여 순환 참조를 방지합니다.
Unowned 참조 참조 대상이 항상 메모리에 남아있거나 한쪽 객체가 다른 객체에 종속적인 경우 사용합니다. 예를 들어, CompanyEmployee에서 Employee는 항상 Company에 종속적이므로 unowned로 설정합니다.

5. 요약

Swift의 강한 참조, 약한 참조, unowned 참조는 객체 간의 관계를 정의하고, 메모리 관리 및 순환 참조 문제를 해결하기 위해 중요한 역할을 합니다.

  • 강한 참조는 기본적인 참조 방식으로, 객체의 소유권을 유지합니다.
  • 약한 참조는 순환 참조를 방지하고, 객체가 해제될 때 nil로 설정됩니다.
  • Unowned 참조는 객체가 항상 메모리에 존재할 때 사용하며, 순환 참조 없이 비옵셔널 참조를 가능하게 합니다.

최종 정리

이와 같이 참조 방식을 상황에 맞게 선택하여 객체 간의 관계를 설정하고 메모리 관리를 효율적으로 할 수 있습니다. Swift의 자동 메모리 관리(ARC) 덕분에, 개발자는 강한 참조와 약한 참조를 적절히 사용하여 메모리 누수 없이 안전한 코드를 작성할 수 있습니다.

728x90

댓글