@escaping (탈출) 키워드
- 원칙적으로 함수의 실행이 종료되면 파라미터로 쓰이는 클로저도 제거된다.
@escaping는 클로저를 제거하지 않고 함수(스택프레임)에서 탈출시킨다. (함수가 종료되어도 클로저가 존재하도록 함)
1. 클로저를 단순 실행 ==> non-escaping 클로저
import Foundation
func performEscaping1(closure: () -> ()) {
print("프린트 시작")
closure()
}
함수 내부에서 단순 실행하고 종료할 때 클로저를 Heap에 저장할 필요가 없다.
@escaping 사용의 대표적인 경우
1. 어떤 함수 내부에 존재하는 클로저(함수)를 외부 변수에 저장하는 경우 ➡️ 파라미터로 받은 클로저를 외부의 변수에 할당하는 경우.
Heap 영역에 저장해서 더 오래 유지하고 사용해야할 경우
var aSaved: () -> () = { print("Closure") }
func performEscaping(closure: @escaping () -> ()){
aSaved = closure
}
perforemEscaping(closure: { print("anotherClosure") }
aSaved()
이렇게 되면 performEscaping함수의 스택프레임을 벗어나게 되며, 외부메모리에 저장된다.
위의 경우엔 aSaved에 performEscaping에 전달된 클로저를 저장하고 있으므로 Heap 영역에 closure의 메모리 공간이 생겨난다. 그 공간을 aSaved변수에 저장하게된다.
파라미터로 전달한 클로저를 외부 클로저 저장소에 담고있다. ➡️ 외부로 탈출시킨다.
컴파일러에게 "파라미터로 받는 함수를 외부로 탈출할거다" 라고 알려주는것.
2. GCD(비동기 코드의 사용)
func performEscaping1(closure: @escaping (String) -> ()) {
var name = "홍길동"
DispatchQueue.main.asyncAfter(deadline: .now() + 1) { //1초뒤에 실행하도록 만들기
closure(name)
}
}
이 코드는 performEscaping1이라는 함수 내부에 정의되어있다.
1초 뒤에 실행한다는 의미는 정의되어있는 함수의 StackFrame을 벗어난다는 의미이다. 는 즉, 저장해 두었다가 1초뒤에 사용하겠다는 뜻이다.
함수의 실행은 name을 생성하고, DispatchQueue.main.async....이 내용을 기다려주지 않고 종료된다.
DispatchQueue.main.async....내부의 내용은 다른 스레드로 넘어가기 때문이다.
closure(name)은 performEscaping1함수의 스택프레임을 벗어나며, 다른쓰레드로 전달된다. performEscaping1함수의 외부에서 실행되므로
함수 내부에서 즉시 사용하는게 아닌 힙 영역에 1초동안 보관하기 때문이다.
위 함수를 실행시켜 보면
performEscaping1 { str in
print("이름 출력하기: \(str)")
}
//...1초뒤
//이름 출력하기: 홍길동
@escaping키워드를 사용하지 않고 외부변수에 저장할 경우 에러가 발생한다.
@escaping 키워드를 사용하여 함수의 실행을 벗어나서 힙영역에 저장할 경우 메모리관리가 필요하다.
@autoclosure 키워드
자동으로 클로저를 만들어줄게!(파라미터가 없는 경우에만)
func someFuction(closure: @autoclosure () -> Bool) {
if closure() {
print("참입니다.")
} else {
print("거짓입니다.")
}
}
//파라미터인 클로저는 Bool을 return하므로 참 혹은 거짓이 된다 즉 if문에 사용 가능
// 파라미터는 클로저로 지정을 했지만 Bool을 입력하게된다. @autoclosure키워드가 붙어있기 때문에 자동으로 중괄호를 삽입하게된다.
someFuction(closure: <Bool>)
someFunction(closure: num == 1)
//아래와 같다 @autoclosure키워드가 중괄호를 삽입해준 느낌
someFunction{ return Bool }
someFunction(closure: { return Bool } )
// Bool값을 나타낼 수 있는 조건만 주면 자동으로 클로저 생성
클로저 형태로 써도 되지만 너무 번거로운 경우 사용.
번거로움을 해결해 주지만, 실제 코드가 명확해 보이지 않을 수 있으므로 사용을 지양해라.(애플공식문서피셜)
잘 사용하지 않는다. 공식 문서를 읽기위해 학습
@autoclosure는 기본적으로 non-escaping 특성을 갖고있는데, escaping 특성이 필요하다면 아래처럼 작성해야한다.
func someClosure(closure: @autoclosure @escaping () -> String{
DispatchQueue.main.ansyncAfter...
}