dev._.note

[Swift] 강한 참조 순환 문제와 해결방법 본문

Dev/SWIFT

[Swift] 강한 참조 순환 문제와 해결방법

Laena 2023. 12. 15. 21:27

강한 참조 순환(Strong Reference Cycle)문제와 해결 방법

  • Swift로 개발할 때에는 메모리 누수(Memory Leak)을 주의.
  • 참조는 디폴트로 강한 참조(Strong Reference)를 사용하는데, 이 강한 참조를 잘못 사용하면 메모리 누수(Memory Leak) 문제가 발생할 수 있음.
  • 가장 대표적인 예가 두 개 이상의 인스턴스가 서로가 서로를 강한 참조일 때 발생합. 이 문제를 강한 참조 순환(Strong Reference Cycle or Retain Cycle)이라고 함.
    • 강한 참조 순환: 메모리가 해제되지 않고 유지되어 메모리 누수가 발생하는 현상
class Man {
    var name: String
    var girlfriend: Woman?

    init(name: String) {
        self.name = name
    }
    deinit { print("Man Deinit!") }
}

class Woman {
    var name: String
    var boyfriend: Man?

    init(name: String) {
        self.name = name
    }
    deinit { print("Woman Deinit!") }
}

var chelosu: Man? = .init(name: "철수")
var yeonghee: Woman? = .init(name: "영희")


chelosu?.girlfriend = yeonghee
yeonghee?.boyfriend = chelosu

chelosu = nil
yeonghee = nil

강한 참조 순환 문제 해결 방법

  1. 약한 참조(Weak Reference): 참조되는 대상을 약하게 참조하여 순환 참조를 방지.
    • *weak*는 옵셔널로 선언되는 참조.
    • 약한 참조는 참조하는 객체를 강제로 유지하지 않고, 참조 대상이 메모리에서 해제되면 자동으로 *nil*로 설정.
    • 주로 순환 참조를 방지하기 위해 사용. 두 객체가 서로를 강하게 참조하는 경우, 순환 참조로 인해 메모리 누수가 발생할 수 있으나 이런 상황에서는 한쪽을 *weak*로 선언하여 순환 참조 문제를 해결가능.
  2. 비소유 참조(Unowned Reference): 참조되는 대상이 항상 유효한 경우에만 사용하며, 해당 대상이 해제될 수 있는 상황에는 사용하지 않음.
    • *unowned*는 옵셔널이 아닌 비소유 참조.
    • 비소유 참조는 항상 값이 있다고 가정하며, 참조하는 객체가 해제되면 런타임 에러가 발생할 수 있음.
    • unowned 참조는 참조 대상이 해제될 수 있는 경우에만 사용. 그리고 그 객체가 메모리에서 해제되지 않은 상태에서만 해당 unowned 참조를 사용.
    // 약한 참조(Weak Reference)를 사용한 해결 방법
    
    class Man {
        var name: String
        weak var girlfriend: Woman?
    
        init(name: String) {
            self.name = name
        }
        deinit { print("Man Deinit!") }
    }
    
    class Woman {
        var name: String
        var boyfriend: Man?
    
        init(name: String) {
            self.name = name
        }
        deinit { print("Woman Deinit!") }
    }
    
    var chelosu: Man? = .init(name: "철수")
    var yeonghee: Woman? = .init(name: "영희")
    
    chelosu?.girlfriend = yeonghee
    yeonghee?.boyfriend = chelosu
    
    chelosu = nil
    yeonghee = nil
    chelosu?.girlfriend // nil
    
    // 비소유 참조(Unowned Reference)를 사용하여 강한 참조 순환 문제를 해결
    class Man {
        var name: String
        unowned var girlfriend: Woman?
    
        init(name: String) {
            self.name = name
        }
        deinit { print("Man Deinit!") }
    }
    
    class Woman {
        var name: String
        var boyfriend: Man?
    
        init(name: String) {
            self.name = name
        }
        deinit { print("Woman Deinit!") }
    }
    
    var chelosu: Man? = .init(name: "철수")
    var yeonghee: Woman? = .init(name: "영희")
    
    chelosu?.girlfriend = yeonghee
    yeonghee?.boyfriend = chelosu
    
    yeonghee = nil
    chelosu?.girlfriend // 에러 발생
    
  • 참고 자료
 

Documentation

 

docs.swift.org

 

'Dev > SWIFT' 카테고리의 다른 글

[Swift] 반응형 프로그래밍  (0) 2023.12.18
[Swift] 동기와 비동기  (0) 2023.12.18
[Swift] 스레드(Thread)  (0) 2023.12.14
[Swift] 프로토콜(Protocol)  (0) 2023.12.13
[Swift] ARC(Automatic Reference Counting)  (0) 2023.12.12