클로저 캡처란 클로저가 매개변수나 지역변수가 아닌 주변 외부의 context를 사용하기 위해 주변 외부의 context를 참조하는 것이다.
캡처는 말 그대로 가져온다는 의미이다. 참조로 가져오니 어떻게 생각하면 원본을 가져오는 것과 의미가 동일하다. 동일한 주소값을 참조하고 있으니, 결국 캡쳐한 값을 변경한다면, 원본의 값도 같이 변경된다.
간단한 예제로는
var num = 0
let c = {
num += 1
print("Check point #1: \(num)")
}
c()
print("Check point #2: \(num)")
위에서 클로저 안에서 num의 값이 변경되고 있다. 이렇게 되면 클로저 c가 num을 캡쳐하고 있는 것이다. 그렇기 때문에, num의 값을 참조하고 있다. 그래서 다시 print 해보면 c의 값이 더 올라간 것을 볼 수 있다.
단순히 생각하면 당연한거 아닌가?? 라는 생각을 할수 있다.
하지만 swift에서 Int 자료형 변수는 값 타입이다. 그래서 일반적으로 global함수로 num을 바꾸고 다시 밖에서 num을 출력한다면 다시 0이 나올것이다. 많은 사람들이 C언어로 swap 함수 만들때 하는 실수와 동일히다.
swift에서도 이런 것이 적용된다. 클로저도 함수이기 때문에, 라이프사이클이 있다. 기본적으로는 라이프사이클 내에서 다 해결하고, 다 끝나면 모든 메모리를 반환하는 게 옳다.
참조를 통해서 함수, 클로저 내에서도 우리는 값을 변경할 수 있다. 이게 곧 Capturing values이다.
애플의 공식예제로 본다면
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0
func incrementer() -> Int {
runningTotal += amount
return runningTotal
}
return incrementer
}
makeIncrementer는 Int형을 받아서 Int 형을 return 하는 closure을 return 한다.
makeIncrementer의 지역변수는 runningTotal이 있다.
func incrementer()라는 클로저에는 runningTotal이라는 주변 외부의 변수를 가지고 있다. 이때 캡쳐가 일어난것이다. 클로저에서 값을 변경하기위해 참조로 변한다.
참조로 캡처를 하게되면 makeIncrementer에 대한 호출이 종료될때, runningTotal과 amount가 사라지지 않으며, 다음에 incrementer 함수가 호출될때 running Total을 사용할 수 있습니다.
결국 클로저의 reference count가 0이 되지 않았다는 소리이다. 그래서 아래의 코드가 가능하다
let incrementByTen = makeIncrementer(forIncrement: 10)
incrementByTen()
// returns a value of 10
incrementByTen()
// returns a value of 20
incrementByTen()
// returns a value of 30| [IOS] DispatchGroup으로 여러 비동기 실행의 마지막을 잡는법 (0) | 2021.08.12 |
|---|---|
| [Swift] escaping closure (0) | 2021.08.02 |
| [SWIFT] Protocol Comparable, Equatable (0) | 2021.07.17 |
| [Swift] Enum 타입의 CaseIterable, CustomStringConvertible?? (0) | 2021.07.17 |
| [Swift] Singleton in Swift, 싱글톤 어떻게 만들까? (0) | 2021.07.17 |
댓글 영역