- 사용자의 코드 안에서 전달되어 사용할 수 있는 로직을 가진 중괄호로 구분된 코드의 블럭이며, 일급 객체의 역할을 할 수 있다.
- 참조 타입
- 일종의 고차함수 인데, 내 생각엔 간단하게 간소화된 함수? 라고 생각한다.
일급 객체는 전달 인자로 보낼 수 있고, 변수/상수 등으로 저장하거나 전달할 수 있으며, 함수의 반환 값이 될 수도 있다.
매개변수나 지역변수 혹은 외부 context를 참조하는 것
=> 외부 context가 없어져도 사용할 수 있음 (Capturing by reference)
이 경우에도 reference count가 1 증가한다.
참조한 변수들을 얼마나 강하게 캡쳐해야하는지를 명시하는 것
{ [] in ~ }
var index = 0
var closureArr: [() -> ()] = []
for _ in 1...5 {
closureArr.append({print(index)})
index += 1
}
for i in 0..<closureArr.count {
closureArr[i]()
}
=> 5 5 5 5 5
var index = 0
var closureArr: [() -> ()] = []
for _ in 1...5 {
closureArr.append({[index] in
print(index)
})
index += 1
}
for i in 0..<closureArr.count {
closureArr[i]()
}
=> 0 1 2 3 4
값타입 => 클로져가 생성될 때 캡쳐
참조타입 => 클로져가 호출될 때 캡쳐
reference count가 초기화 되지 않고 화면 이동이 일어났을 때 메모리 누수 발생 (순환 참조 등)
=> 캡쳐 리스트로 해결 가능 (weak , unowned)
unowned는 nil이 들어오는 것을 처리할 수 없기 때문에 조심히 사용해야한다.
closure를 optional로 지정하면 더이상 closure타입이 아닌 optional타입이 된다.
() -> () : closure (() -> ())? : optional
결론적으로 optional closure를 사용하면 기존의 일반 파라미터 처럼 사용이 되면서 자동으로 escaping으로 변경되기 때문에 escaping키워드를 사용하지 않아도 된다.
closure는 기본적으로 non-escaping
=> 함수가 종료되고 나서 클로저가 실행될 수 없다.
함수 내부에서 직접 실행하기 위해서만 사용 (함수가 종료되기 전에 무조건 실행 되어야 하는 경우)
파라미터로 받은 closure를 비동기로 사용하고 싶을 때 사용
=> 함수의 흐름에 상관 없이 실행되는 클로저