[iOS] Strong, Weak, Unowned 와 순환 참조 (약한 참조, 강한 참조)

kimdocs...📄·2021년 8월 1일
0

iOS

목록 보기
15/22
post-thumbnail

강한 참조

  • 기본적으로 Swift에서는 참조하는 대상에 대해 강한 참조를 유지한다.
  • 객체 간의 강한 참조가 형성되면 참조 대상은 메모리에서 해제되지 않는다.
  • 강한 참조는 순환 참조(circular reference)를 유발할 수 있어 메모리 누수(memory leak)의 원인이 될 수 있다.

약한 참조

  • 인스턴스를 참조시 Reference Count가 증가하지 않으며 참조하던 인스턴스가 메모리에서 해제된 경우 (nil이 된 경우) 자동으로 nill이 할당되어 메모리가 해제된다.

순환 참조란?

  • 두 개의 객체가 서로가 서로를 참조하고 있는 형태!

예시)

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

var person1: Person? = Person(name: "John")
var person2: Person? = Person(name: "Sarah")

// 강한 참조
person1?.friend = person2
person2?.friend = person1

// 순환 참조가 형성되어 메모리에서 해제되지 않음

// 약한 참조
weak var weakPerson1 = person1
weak var weakPerson2 = person2

person1 = nil
person2 = nil

print(weakPerson1)  // nil
print(weakPerson2)  // nil

위의 예시에서 person1과 person2 간에 강한 참조가 형성되어 순환 참조가 발생한다. 이 경우, person1과 person2는 메모리에서 해제되지 않는다.
하지만, weakPerson1과 weakPerson2는 약한 참조로 선언되어 있으므로 person1과 person2가 nil로 설정된 후에는 자동으로 nil로 설정된다!

문제점

  • 서로가 서로를 참조하고 있어서 Reference Count가 0이 되지 못한다.
  • 해당 인스턴스를 가리키던 변수에 nil값을 넣는 다면 인스턴스에 접근할 수 있는 방법도 없어 메모리 해제가 불가능 함.
  • 어플이 죽기 직전까진 memoy leak이 계속 발생하게 됨
  • 이렇게 strong을 사용해서 순환참조에 문제가 생긴 경우를 강한 순환 참조라 부름 -> 강한 순환 참조를 해결하기 위해 weak과 unowned를 사용하자!!

Strong

  • Strong은 객체를 소유하여 Reference Count가 증가하는 프로퍼티이다.
  • 값 지정 시점에 retain이 되고 참조가 종료되는 시점에 release된다.
  • 레퍼런스 카운트를 증가시켜 ARC로 인한 메모리 해제를 피하고 객체를 안전하게 사용하고자 할 때 쓰인다.
  • 별도의 키워드를 적지 않는 다면 strong이 default값이다.

Weak

  • Weak은 객체를 소유하지 않고 주소값만을 가지고 있는 포인터 개념이다.
  • 자신이 참조는 하지만 weak 메모리를 해제시킬 수 있는 권한은 다른 클래스에 있다.
  • 값 지정시 리테인이 발생하지 않는 다. 따라서 릴리즈도 발생하지 않는다. 그래서 언제 어떻게 메모리가 해제될 지 알 수가 없다.
  • 다만 메모리가 해제될 경우 자동으로 레퍼런스가 nil로 초기화를 해준다.
  • 그렇기 때문에 weak 속성을 사용하는 객체는 항상 옵셔널 타입이어야한다.
  • retain cycle에 의해 메모리가 누수되는 문제를 막기위해 사용되며 Delegate가 그 예시다.

Unowned

  • Unowned는 Weak와 매우 비슷한 역할을 한다.
  • 차이점으로 Unowned로 선언된 변수는 nil이 될 수가 없다.
  • 그러므로 옵셔널로 선언되어서는 안된다.
  • 해제된 메모리 영역을 접근하지 않는 다는 확실한 경우에만 사용해야한다.
  • 참조 대상이 이미 해제되었는 데 unowned self를 사용하면 런타임 에러인 Unexpectedly found nil while unwrapping an Optional value가 발생한다.
  • 즉 객체의 라이프 사이클이 명확하고 개발자에 의해 제어 가능이 명확한 경우에 사용해야한다.

클로저 블럭내에서 [weak self] in 코드를 넣는 방법으로 순환 참조를 해결하는데, 이때 [weak self] in 코드가 하는 역할과 그 이유는?

  • [weak self] 의 역할로는 ARC가 프로퍼티의 갯수를 카운팅 하지 않도록 만들며 카운팅이 되지 않기에 순환참조가 일어나지 않도록 만드는 역할 한다.
  • 그 이유로는 weak 참조는 ARC에 의해 참조되는 인스턴스가 메모리에서 해제 될 때 프로퍼티의 값을 nil로 만들기 때문에 순환 참조가 발생하지 않는다.

[weak self]는 항상 써야할까?

  • self가 강한 참조 되지 않는 경우에는 weak self를 사용할 필요가 없다.
profile
👩‍🌾 GitHub: ezidayzi / 📂 Contact: ezidayzi@gmail.com

0개의 댓글