[Swift] capture, capture list

·2024년 7월 2일
0

Swift 문법

목록 보기
10/16

캡처

클로저는 정의된 둘러싸인 컨텍스트에서 상수와 변수를 캡처 (capture)할 수 있습니다. 그러면 클로저는 상수와 변수를 정의한 원래 범위가 더이상 존재하지 않더라도 본문 내에서 해당 상수와 변수의 값을 참조하고 수정할 수 있습니다.
Swift document: Closures


캡처란

클로저 내부에서 외부의 값을 사용하기 위해, 해당 값을 클로저 내부적으로 저장하는 것
이것을 클로저에 의해 값이 캡처되었다‼️라고 함
캡처해서 가지고 있다가, 필요할 때마다 사용하는…!

이러한 정의를 이용해서 블럭을 해석해 보면,
클로저는 주변의 context에서 상수와 변수 값을 클로저 내부에 저장할 수 있다는 것.
여기서의 context는 클로저 주변의 함수와 같은 코드를 의미


캡처하기

예를 들어, 다른 함수 본문 내에 작성하는 중첩 함수는
바깥 함수의 인수와 바깥 함수 내에 정의된 상수와 변수를 캡처할 수 있음

func makeIncrementer(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0

    func incrementer() -> Int {
        runningTotal += amount
        return runningTotal
    }
    return incrementer
}

incrementer() 함수를 포함하는 makeIncrementer(forIncrement) 함수를 정의하였다.

  • amount 파라미터에 전달된 인수 값은 makeIncrementer(forIncrement) 함수가 호출될 때마다 얼마나 증가시켜야 할지를 지정
  • 실제로 runningTotalamount 만큼을 더하여 실제로 증가시키는 incrementer() 함수

이때, runningTotalamount 에 대한 참조를 캡처하기 때문에,
runningTotalamount 가 사라지지 않고
다음 incrementer() 함수 호출 시에 해당 runningTotalamount 를 사용함.


클로저도 reference type이기 때문에,
메모리에서 사라지는 순간까지 runningTotalamount 는 계속해서 잡혀 있게 된다.

let incrementByTen = makeIncrementer(forIncrement: 10)
incrementByTen() // 10
incrementByTen() // 20
incrementByTen() // 30

이렇게 incrementByTen() 을 호출할 시에,
캡처한 runningTotal 을 계속해서 사용하는 것이다.
따라서 결과는 계속해서 10, 20, 30… 으로 증가하게 된다.


나는 runningTotal 을 참조해서 사용하고 싶지 않은데…
그냥 해당 값을 사용하고 싶은데… ,,,
이럴 때는 클로저의 캡처리스트를 사용하면 된다.



클로저의 캡처리스트

캡처리스트는 클로저에서 값이 캡처되는 방법을 명시적으로 제어할 수 있다.

  • 항목들을 in 키워드 앞에, [ ] 내에 넣어 작성
  • 캡처 리스트의 항목들은 클로저가 생성될 때 초기화
  • 주변 범위에서 이름이 같은 상수 또는 변수의 값으로 초기화

case 1) 캡처 리스트에 value type을 추가한 경우

  • 캡처리스트 x
var a = 0
var b = 0

let closure = {
    print(a, b)
}

a = 10
b = 10
closure() // 10 10 
var a = 0
var b = 0

let closure = { [a] in
    print(a, b)
}

a = 10
b = 10
closure() // 0 10
  • 캡처 리스트를 통해 a를 캡처
  • 클로저 캡처 리스트 항목 a 는 클로저가 생성될 때, 외부의 a 변수의 값으로 초기화됨
    • 하지만 두 개가 연결된 것은 ❎
    • 따라서 외부 변수 a 가 변경되더라도 영향을 받지 않음
    • if 클로저 내부에서 a 를 변경하려 한다면?
      항목을 상수로 캡처하기 때문에, value type capture된 값을 변경할 수는 없음

case 2) 캡처 리스트에 reference type을 추가한 경우

  • 캡처리스트 x
class TestClass {
    var value = 0
}

var a = TestClass()
var b = TestClass()
let testClosure = { print(a.value, b.value) }

a.value = 10
b.value = 15
testClosure() // 10 15
  • 캡처리스트 o
class TestClass {
    var value = 0
}

var a = TestClass()
var b = TestClass()

let testClosure = { [a] in
    print(a.value, b.value)
}

a.value = 10
b.value = 15
testClosure() // 10 15
  • 캡처 리스트를 통해 a 를 캡처했지만, value type capture은 되지 않음을 알 수 있음


정리

클로저 내부에서 주변의 context(환경, 코드… etc)의 값의 참조를 캡처하여 내부에서 사용할 수 있도록 하는 것을 캡처라고 한다.

캡처리스트에서는 이러한 캡처의 방식을 제어할 수 있는데,
캡처리스트에 value type 포함 시에 value type 캡처를 진행할 수 있다.
캡처리스트에서 reference type 포함 시에는 value type 캡처가 불가능하다.

0개의 댓글

관련 채용 정보