Closure의 Capture

4 답변 글타래를 보이고 있습니다
  • 글쓴이
    • Lena
      참가자
      • 글작성 : 4
      • 답글작성 : 5

      오늘은 메모리 관점에서 클로저에 대해서 학습했습니다.

      1. 클로저는
      `swift
      func makelncrementer(forlncrement amount: Int) -> (() -> Int) {
      var runningTotal =0
      func incrementer() -> Int {
      runningTotal += amount return runningTotal
      }
      return incrementer
      }

      let incrementByTwo: (()->Int) =makelncrementer(forlncrement: 2)
      let sameWithlncrementByTwo: (() -> Int ) = incrementByTwo
      let first: Int =incrementByTwo() // 2
      let second: Int =sameWithlncrementByTwo() // 4
      `
      클로저는 자신이 정의된 위치의 주변 문맥을 통해 상수나 변수를 획득(capture)할 수 있습니다. 값 획득(Capture)을 통해 클로저는 주변에 정의한 상수나 변수가 더 이상 존재하지 않더라도 해당 상수나 변수의 값을 자신 내부에서 참조하거나 수정할 수 있습니다.

      상수에 클로저를 할당한다는 것은 클로저의 값을 할당하는 것이 아니라 해당 클로저의 참조를 할당하는 것입니다.

      2. 클로저는 클래스와 마찬가지로 Reference Type
      값 전달할 때 마다 stack에 주소가 복사됩니다.
      참조 방식에서 ‘참조’는 stack에 저장되어있는 주소를 의미합니다.

      3. 클로저의 캡쳐와 캡쳐리스트를 통한 캡쳐
      `swift
      var firstOne = 0
      var secondOne = 0
      let closure = {print (firstOne,secondOne)}
      firstOne = 1
      secondOne = 2
      closure() // 결과 : 1,2
      `

      closure 상수에 저장된 클로저는 firstOne, secondOne 두 상수를 캡쳐합니다.
      클로저가 값을 캡쳐할 땐 복사본이 아니라 참조(값의 주소, reference)가 전달합니다. 두 변수를 변경하고 클로저를 호출하면 클로저가 생성된 시점에 두 변수에 저장되어있던 값이 아니라 변경된 현재 값이 출력됩니다.

      `swift
      var firstOne = 0
      var secondOne = 0
      let closure = { [firstOne] in print (firstOne, secondOne)}
      firstOne = 1
      secondOne = 2
      closure() // 결과 : 0,2
      `

      하지만 캡쳐 리스트(Capture List)를 통해 firstOne을 캡쳐하면 이전과 달리 참조가 전달되지 않습니다. 왜냐하면 firstOne에 저장되어있는 값과 동일한 값을 가진 상수 복사본이 전달되기 때문입니다. 그래서 클로저를 선언한 후(3번째 라인)에 fisrtOne 값을 변경하더라도, 변경되지 않은 클로저에서 캡쳐된 firstOne의 값이 출력됩니다. 즉, 캡쳐 대상으로 지정한 firstOne은 값이 복사되서 전달됐으므로 0이 출력됩니다.

      3. 클로저 내 self

      `swift
      class Person{
      var name = “Lena”
      var job = “developer”
      lazy var nameTag: () -> String = {
      return self.name + self.job
      }
      }
      `

      클로저는 self 키워드를 통해 인스턴스 속성에 접근합니다. self는 인스턴스 자체를 나타내는 속성으로, 클로저에서 사용하면 self가 캡쳐됩니다. 위 예제 코드(3번)에서는 selfPerson이라는 클래스이고 이 클래스 인스턴스를 캡쳐합니다. 그리고 이 클래스의 속성인 namejob에 접근합니다. 클로저는 자신의 실행이 종료될 때 까지 self가 메모리에 유지되도록 강한참조로 캡쳐합니다. 이 클로저는 인스턴스 속성(Person이라는 클래스의 프로퍼티)에 저장됩니다.
      (3번 예제 코드는 클로저의 강한참조 순환문제가 일어나는 코드입니다. 이 문제는 Capture List로 해결할 수 있습니다.)

      참고한 자료 :
      ‘스위프트 프로그래밍 3판’ (지은이: 야곰)
      ‘Closures — The Swift Programming Language (Swift 5.2)’
      https://docs.swift.org/swift-book/LanguageGuide/Closures.html

    • 야곰
      키 마스터
      • 글작성 : 37
      • 답글작성 : 579

      @Lena

      (3번)에서는 self가 Person이라는 클래스이고 이 클래스 인스턴스를 캡쳐합니다.라는 표현이 있었는데요,
      [selfPerson이라는 클래스의 인스턴스] 라는 표현이 더 적절하지 않을까요? 제가 착각한건지 궁금합니다 🙂

    • 야곰
      키 마스터
      • 글작성 : 37
      • 답글작성 : 579

      @Lena
      (3번)에서는 self가 Person이라는 클래스이고 이 클래스 인스턴스를 캡쳐합니다.라는 표현이 있었는데요,
      [selfPerson이라는 클래스의 인스턴스] 라는 표현이 더 적절하지 않을까요? 제가 착각한건지 궁금합니다 🙂

    • Lena
      참가자
      • 글작성 : 4
      • 답글작성 : 5

      아 맞아요! 제가 표현을 잘못한것 같네요 피드백 감사합니다:)

    • Lena
      참가자
      • 글작성 : 4
      • 답글작성 : 5

      아 맞아요! 제가 표현을 잘못한것 같네요 피드백 감사합니다:)

4 답변 글타래를 보이고 있습니다
  • 답변은 로그인 후 가능합니다.

logo landscape small

사업자번호 : 743-81-02195
통신판매업 신고번호 : 제 2022-충북청주-1278 호
고객센터 : 카카오톡채널 @yagom