Programing Langauge/swift

클로저와 self

Hamp 2024. 10. 23. 20:41
반응형

클로저

간단하게 클로저를 먼저 정리해보자.

  • 함수는 이름이 있는 클로저
  • 클로저는 1급 객체이다.
  • 클로즈는 참조타입이므로 기본적으로 힙에 할당된다.
  • Closure 내부 함수와 내부 함수에 영향을 미치는 주변 환경을 모두 포함한 객체이다.

클로저 캡처

  • 클로저 캡처란 매개변수나 지역변수가 아닌 외부 context 사용하기 위해 주변 외부의 context 참조하는 것
  • 클로저는 값을 캡처할 때, Value / Reference 타입에 관계 없이 모두 Reference 캡처를 사용한다. 즉 , 참조를 한다는 뜻

캡처 리스트 

  • 값 타입은 값을 복사해서 캡처 - 외부 요인에 의한 값 변경을 방지!
  • 참조 타입은 캡처리스트 내에서 weak, unowned 참조 선언 (강한 참조 해결)

클로저와 self 

@escaping 키워드

클로저와 self의 관계를 가기전에 @escaping 키워드에 대해 잠시 알아보자.

var 함수저장변수: (() -> Void)?

/// @escaping 키워드 파라미터가 지금 실행되고 있는 스코프를 벗어나서도 쓰인다.

func 탈출클로저(함수파라미터: @escaping () -> Void) {
    함수저장변수 = 함수파라미터 // 외부 변수에 클로저(참조타입) 저장되면 힙에 저장되어 오래쓰임 
    // 캡처현상이 발생 가능 O
}


/// 인풋(함수파라미터)가 힙(Heap)에 저장이 안됨(오랫동안 쓰이지 않음) ===> 캡처현상이 발생 X

func 기본클로저(함수파라미터: () -> Void) {
    함수파라미터() // 외부 스코프로 나가지 않음, 힙에 저장 x , 캡쳐핸상 발생 x
}

 


클래스에서 클로저

  self 캡처 여부 이유
탈출 클로저 O 변수를 소유하고 있는 self 자체를 캡처하기
때문에
기본 클로저 X 암시적으로 self를 참조

 

class 클래스 {
    var x = 10
    
    func doSomething() {
        탈출클로저 { in   
            self.x = 100 /// 명시적 self 참조, 나중에 호출시 실행
        }
        기본클로저 {   /// 즉시 실행
            x = 200 /// 암시적 self참조
        }
    }
}
  • 클래스에서 탈출 클로저는 항상 self를 붙혀야한다. 혹은 캡처 리스트 작성
  • 기본 클로저는 self를 붙히지 않아도 됨, 암시적으로 self를 참조

값타입에서 클로저

  self 캡처 여부 이유
탈출 클로저 오류 self에 대한 변경이 불가
값타입이니 값 복사가 일어나
원본을 바꿀 수 없으므로 
기본 클로저 X 암시적으로 self를 참조

 

struct 구조체 {   // 값타입
    var x = 10
    
    mutating func doSomething() {
        기본클로저 {
            x = 200          /// Ok  (암시적으로 self참조)
        }
        
        // ❌ 에러 발생
        탈출클로저 {
            self.x = 100 
        }                   
    }
}
  • 값 타입의 self 일경우 항상 암시적으로 self를 참조
  • 위의 예시에서 doSomething 함수 내부에서 탈출 클로저를 호출하는 것은 오류다.
  • mutating  함수 스코프에서 변수값을 바꾸는게 아닌 탈출클로저로 인해 외부 스코프에서 구조체(값타입)에 대해
    변경하는 것이기 때문에 잘못된 사용이다.

참고

 

Documentation

 

docs.swift.org

 

반응형