티스토리 뷰

IOS/swift

[Swift] 클로저와 메모리 관리

내일도이렇게 2022. 4. 6. 12:10

클로저는 클로저의 주기동안 사용이 필요 없어질때까지 힙 영역에 존재하고, 내부에서 클로저 외부에 존재하는 변수를 계속 사용해야 하기 때문에 갭쳐가 발생된다.

(캡쳐: 클로저 내부에서 밖에 있는 스코프의 인스턴스를 참조하는 것) 

 

클래스 인스턴스에서 강한 참조 사이클이 발생하듯이 클로저에서도 강한 참조 사이클이 발생할 수 있다. 

이러한 강한 참조 사이클을 방지하기 위해 캡쳐리스트를 사용하여 방지한다.

 

캡쳐리스트를 사용하여 순환 문제 해결

 

gasMileage 클로저 에서 self 를 통해 Car 클래스 내부의 인스턴스를 참조할때 강한 참조 사이클를 발생하여 myCar 에 nil 을 대입해도 메모리 해제가 안되고 있다. 

class Car {
    var totalDrivingDistance = 0.0
    var totalUsedGas = 0.0

    lazy var gasMileage: () -> Double = {
        return self.totalDrivingDistance / self.totalUsedGas
    }

    func drive() {
        self.totalDrivingDistance = 1200.0
        self.totalUsedGas = 73.0
    }

    deinit {
        print("Car deinit")
    }
}

var myCar: Car? = Car()
myCar?.drive()
myCar?.gasMileage()

myCar = nil

 

캡쳐리스트 문법

{ [list] (parameters) -> ReturnType in
    // Code
}

{ [list] in
    // Code
}

 

클로저 캡쳐리스트 약한 참조 [weak self] 을 이용하여 실행해보면 deinit 이 호출 되는걸 확인 할 수가 있는데 

강한 참조 사이클을 해결할 수 있다. 

class Car {
    var totalDrivingDistance = 0.0
    var totalUsedGas = 0.0

    lazy var gasMileage: () -> Double = { [weak self] in
        guard let self = self else { return 0.0 }
        return self.totalDrivingDistance / self.totalUsedGas
    }

    func drive() {
        self.totalDrivingDistance = 1200.0
        self.totalUsedGas = 73.0
    }

    deinit {
        print("Car deinit")
    }
}

var myCar: Car? = Car()
myCar?.drive()
myCar?.gasMileage()

myCar = nil


// print Car deinit

Reference

https://velog.io/@delmasong/Closure-Capture-List


https://onelife2live.tistory.com/12

'IOS > swift' 카테고리의 다른 글

iOS 구글 로그인 연동  (0) 2024.01.21
[Swift] GCD ( DispatchQueue) 정리  (0) 2022.04.08
[Swift] ARC  (0) 2022.04.05
[Swift] Method Dispatch 와 성능 최적화  (0) 2022.04.05
[Swift] Optional  (0) 2022.03.22
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함