Escaping Closure
- @Escaping 란?
함수가 종료된 후에도 클로저를 사용할 때 쓰는 키워드
- 기본적으로 함수의 파라미터로 전달된 클로저는 함수 내부에서만 사용할 수 있지만, 함수가 종료된 후에도 클로저를 사용할 경우
@escaping 키워드 사용
- 클로저는 기본값이
non-escaping
- 파라미터로 받은 클로저는 다른 변수나 상수에 할당 불가
- 파라미터로 받은 클로저는 함수의 실행이 완료되기 전에 함수 내부에서 클로저를 사용해야 함
func testEsacpingClosure(closure: () -> Void) {
closure()
}
testEsacpingClosure {
print("Hello")
}
import UIKit
func testEsacpingClosure(closure: () -> Void) {
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
closure()
}
}
func testEsacpingClosure(closure: () -> Void) {
let newClosure: () -> Void = closure
}
@escaping closure는 주로 비동기적인 작업 후 클로저 호출시 사용
- 예시 : 서버에서 API 호출시 서버의 응답을 기다린 후 데이터를 받아 처리하는데, 이때 서버 응답이 오기 전에 함수가 먼저 종료될 수 있음. 따라서
@escaping을 사용해 서버 응답을 받은 후 클로저 호출.
import UIKit
func testEsacpingClosure(closure: @escaping () -> Void) {
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
closure()
}
}
testEsacpingClosure {
print("클로저 실행")
}
클로저 캡처 (closure capture)
- 클로저 캡처란?
클로저가 컨텍스트(자신이 생성된 코드블럭) 내에 있는 변수, 상수에 접근하는 것
- 클로저는
참조 형식으로 값을 사용. 즉, 값이 변경되면 캡처된 값도 변경된 값 출력
- 클로저가 선언된 뒤 선언된 변수, 상수는 클로저로 사용할 수 없음
struct Person {
var name: String
var age: Int
}
func testClosureCapture() {
var person = Person(name: "Brody", age: 20)
let closure = {
print(person.age)
}
closure()
person.age = 25
closure()
}
testClosureCapture()
func testClosureCaptureError() {
var a = 1
let closure = {
print(a)
print(b)
}
var b = 1
}
캡처 리스트
- 캡처리스트란?
클로저가 주변 환경의 변수를 캡처할 때 메모리 관리를 명시적으로 제어할 수 있는 방법
- 클로저는
Value Type의 값도 참조로 캡처하지만 Value Type으로 참조할 수 있음
reference type 은 참조방식을 정할 수 있음
[ ] 대괄호 안에 사용할 변수나 상수를 작성하여 캡처리스트를 정할 수 있다
Reference Type 참조 방식 정하기
- 기본은
strong이기 때문에 강한순환참조가 발생할 수 있음
- 대괄호를 사용하고 참조방식과 캡처할 변수(상수) 이름을 작성
weak, unowned 사용 가능
class Animal {
var name: String
var age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
}
func testClosureCaptureReference() {
var animal = Animal(name: "Dog", age: 1)
let closure = { [weak animal] in
print(animal?.age)
}
closure()
animal.age = 2
closure()
}
testClosureCaptureReference()
Value Type 으로 캡처하는 방법
struct Person {
var name: String
var age: Int
}
func testClosureCapture() {
var person = Person(name: "Brody", age: 20)
var a = 1
let closure = { [person] in
print(person.age)
print(a)
}
closure()
person.age = 25
a = 2
closure()
}
testClosureCapture()