Swift/Swift 문법

[클로저 - 4] 클로저의 캡처

내일은개발천재🎵 2022. 12. 29. 16:39

클로저의 메모리 구조

  • 클로저는 참조형식이다. (Reference Type)
    • 필요 시 메모리의 주소를 전달한다.
    • 값은 Heap 영역에, 주소는 Stack 영역에 저장한다.
    • ⇒ 코드 영역의 메모리 주소를 Heap에 저장하며, 실행은 Stack 프레임에서 실행된다.
  • RC를 통해 메모리를 관리한다. (Swift - ARC)

클로저의 캡처

var stored = 0

let closure = { (number: Int) -> Int in
	stored += number
	return stored
}

closure(3) // 3
closure(4) // 7
closure(5) // 5
stored = 0
closure(5) // 5
  • closure 내부에서 stored라는 외부 변수를 사용한다.
    • 외부 변수를 계속해서 사용해야하기 때문에 Heap에 해당 값을 저장한다.
    • 저장할 값의 참조 값을 저장하는 것(주소) → 지속적인 참조의 가능

캡처현상

  • 함수가 외부 변수에 있는 값을 사용해야할 때 발생하는 현상이다.
    • 클로저 뿐만 아니라, 중첩함수에서도 발생한다.
  • 메모리 구조 상, 클로저는 실행 후 Stack에서 사라지는데, Heap 영역에는 남아있다.
    • Heap 영역에 외부 변수 값을 저장해서 지속적으로 사용하는 것이다.
    • Reference Type이어서 발생하는 현상이라고 볼 수 있다.
// 캡처 현상이 없는 일반 함수
func calculate(number: Int) -> Int {
	var sum = 0

	func square(num: Int) -> Int {
		sum += (num * num) 
		return num
	}

	let result = square(num: number)

	return result
}

calculate(number: 10)   // 100
calculate(number: 20)   // 400
calculate(number: 30)   // 900
// 캡처현상, Heap 영역에 특정 값을 유지한다.

func calculateFunc() -> ((Int) -> Int) {
	var sum = 0

	func square(num: Int) -> Int {
		sum += (num * num) // Heap에 저장되어 지속적으로 사용해야한다.
		return num)
	}

	return square // 함수를 Return -> 값을 지속적으로 저장한다.
}

var squareFunc = calculateFunc()

squareFunc(10)    // 100
squareFunc(20)    // 500
squareFunc(30)    // 1400
  • sum은 함수 외부에 존재하는 변수인데, sum이 사라지면 에러가 발생한다
  • → Heap에 저장하는 캡처 현상이 발생한다.
  • 변수에 할당하지 않고, 직접적으로 실행하면 캡처 현상이 일어나지 않는다.
    • Stack Frame만 활용하게 되기 때문이다.
    • 변수에 저장할 때에만 Heap에 저장된다.

느낀점 : 캡처리스트 너무 어렵다........ ARC 제대로 공부하고 다시 공부해서 포스팅 할 예정 !!!

앨런님의 Swift 강의를 보고 정리한 글입니다.