탈출 클로저 (@escaping closure)
13 Jun 2018 | swift 스위프트 클로저 closure escaping@escaping
함수 사이에 실행 순서를 정하고 싶을때 Escaping Closure를 사용한다. 비동기 처리시 유용하다.
발견
- 주소록앱 미션 중 연락처를 fetch해오는 과정에서 테이블뷰 화면이 표시되지 않는 문제 발생.
- 하지만 디버깅해보니 연락처는 다 정상적으로 가져와짐.
- 문제는 연락처를 request하는 함수가 비동기로 처리되는거라 연락처가 다 fetch되지 않은 상태에서 테이블뷰를 load했기 때문.
- 연락처가 모두 fetch되는 비동기로 처리되는 동작이 모두 끝난 후 뷰를 다시 로드해야 했기 때문에 함수 사이에 실행순서를 보장하고 싶어서 escaping(탈출 클로저) 사용.
나만의 결론
- 함수를 벗어나서도 클로저를 유효하게 사용(호출, 저장 - outLive)하고싶을 때 escaping을 사용한다!
- escaping을 사용하면 A 함수가 마무리된 상태에서만 B 함수가 실행되도록 작성할 수 있다.
- 이는 비동기로 실행되어 실행 직후 반환되어버리는 함수 동작과 관련하여 동작 순서를 정해줄때 매우매우 유용하다.
예시 코드
// 함수 외부에 클로저를 저장하는 예시
// 클로저를 저장하는 배열
var completionHandlers: [() -> Void] = []
/*
함수 밖에 있는 completionHandlers 배열에 해당 클로저를 저장.
즉, 클로저가 함수에서 빠져나감.
이렇게 함수를 호출하는 도중에 해당 함수 외부에 클로저를 저장하기 위해서는
Escaping Closure이어야 함.
*/
func withEscaping(completion: @escaping () -> Void) {
completionHandlers.append(completion)
}
func withoutEscaping(completion: () -> Void) {
completion()
}
class MyClass {
var x = 10
func callFunc() {
withEscaping { self.x = 100 }
// 만약 여기서 self키워드를 안쓰면 아래의 에러가 발생한다.
// Reference to property 'x' in closure requires explicit 'self.' to make capture semantics explicit. Insert self.
// 클로저에서 속성에 접근할때는 self.키워드 명시해야함
withoutEscaping { x = 200 }
// 근데 이것도 클로저 아닌가?
}
}
let mc = MyClass()
mc.callFunc() // x=200코드가 withoutEscaping의 인자로 들어가서 그냥 실행되어버림
print(mc.x) // callFunc()를 호출하면서 변경된 x값 출력
completionHandlers.first?() // array에 저장된 첫번째 클로저 실행
print(mc.x) // callFunc()를 호출하면서 withEscaping이 실행되어서 클로저가 저장되었고,
// array에 저장된 첫번째 클로저가 실행되면서 변경된 x=100 출력
// 결과
// 200
// 100
Comments