본문 바로가기
Swift

[Swift] lazy var 사용 시 retain cycle 주의

by Sky Titan 2023. 1. 16.
728x90
 

[iOS - swift] lazy var 클로저 사용 주의 (리테인 사이클, 메모리 릭)

Lazy var 클로저 사용시 주의사항 lazy var 클로저 사용 시 retain cycle이 발생하는지? 아래 1)번과 2)번 구분 (아래에서 계속) 1) private let text = "label" private lazy var label: () -> UILabel = { let label = UILabel() label.

ios-development.tistory.com

 lazy var는 어떠한 연산을 통해 변수를 생성하기 위해서 closure를 사용하게 된다.

 

이 때 아래와 같이 블록{} 마지막에 () 가 붙은 형태는 nonescaping closure라고 해서 실행 즉시 결과를 반환함을 가정하기 때문에 클로저 내부에서 self를 명시적으로 참조할 필요가 없고, self instance의 retain count를 올리지도 않기 때문에 retain cycle에 대한 걱정도 없다.

    lazy var greeting: String = {
        return "Hello my name is \((name))"
    }()

 

 반면 아래와 같은 형태로 closure를 타입으로 선언 후 사용하면 self를 명시적으로 참조해야 하고, closure가 실행되고 나서도 self의 retain count가 증가한 상태로 유지되기 때문에 retain cycle이 발생할 수 있다.

lazy var greeting: () -> String = {
     return "Hello my name is \((self.name))"
}

 

안전한 사용 예시

import Foundation
class Person {
    var name:String
    deinit {
        print("deinit")
    }
    lazy var greeting: String = {
        print("클로저 내부 참조 \(CFGetRetainCount(self))")
        return "Hello my name is \((name))"
    }()
    init(name:String){
        self.name = name
    }
}

func call() {
    var me = Person(name:"John")
    print(CFGetRetainCount(me))
    print(me.greeting) // Hello my name is John
    print(CFGetRetainCount(me))
}

call()

/* 
2
클로저 내부 참조 2
Hello my name is John
2
deinit
*/

 위와 같이 greeting에 nonescaping closure 사용 시 instance의 참조횟수가 증가하지도 않고 deinit이 정상적으로 호출되는 걸 확인할 수 있다.

 

Retain Cycle 발생 예시

import Foundation
class Person {
    var name:String
    deinit {
        print("deinit")
    }
    lazy var greeting: () -> String = {
        print("클로저 내부 참조 \(CFGetRetainCount(self))")
        return "Hello my name is \((self.name))"
    }
    init(name:String){
        self.name = name
    }
}

func call() {
    var me = Person(name:"John")
    print(CFGetRetainCount(me))
    print(me.greeting()) // Hello my name is John
    print(CFGetRetainCount(me))
}

call()

/*
2
클로저 내부 참조 4
Hello my name is John
3
*/

 위와 같이 일반적인 closure를 사용하여 weak capture없이 self를 참조하면 retain cycle이 발생하게 된다.

728x90

댓글