-
728x90
@escaping
Swift document - escaping은 탈출 클로저로 함수을 말한다.
- 함수가 반환된 후 실행 되는 것을 의미한다.
- 클로저의 escaping은 A 함수가 마무리된 상태에서만 B 함수가 실행되도록 함수를 작성할 수 있다는 점에서 유용하다.
- 클로저 인자를 함수 밖에서도 연장(Outlive)이 필요할 때 사용한다.
공모전에 나가서 네트워크 통신을 위해 Alamofire 라이브러리를 사용했을 때 동기와 비동기 문제로 고민했던 경험을 예로 설명을 하자면
로그인 코드 지금은 지워서 기억이 나지 않지만 이 전에 작성했던 코드에서 실행 순서를 보장 받지 않아서 서버의 응답 값과 View 전환이 엇박자를 타서 애를 먹었던 적이 있다. 아직 개념이 부족했던 터라 Lifecycle의 문제인 줄 알고 삽질을 했었는데, 결국 많은 검색 끝에 Alamofire는 비동기 기반으로 네트워크 응답을 처리하기 때문에 발생한 버그임을 알았다.
Alamofire.request(urlRequest) 메소드는 서버로 Request를 전송한다. 그리고 그 결과는 Response 객체를 통해 받을 수 있는데 일반적으로 서버에 Request를 전송하고 그 Response 받아오는 함수들은 비동기로 작동하여 Request를 보낸 직후 반환 되어버린다. 따라서 Request 결과를 기다리게 하는 형태로 함수를 작성해야 했고 @escaping closure가 필요했다.
responseJSON를 자세히 들여다 보면
@discardableResult public func responseJSON( queue: DispatchQueue? = nil, options: JSONSerialization.ReadingOptions = .allowFragments, completionHandler: @escaping (DataResponse<Any>) -> Void) -> Self { }
queue와 options는 기본값이 지정되어 있어 값을 주지 않아도 되지만 completionHandler는 @escaping 형태로 작성되어 있는 것을 알 수 있다. 즉 completion은 responseJSON()이 서버로부터 값을 가져오고 반환이 되어야 실행되는 것이다.
따라서 값을 반환받고 @escaping형태의 { response in ... } 부분을 case .success와 .failure로 처리하여 더이상 오류가 발생하지 않게 되었다.
@escaping 클로저를 함수 외부에서 저장
class Myclass { var x = 0 func callFunc() { withEscaping { self.x = 100 } withoutEscaping { x = 200 } } var completionHandlers: [() -> Void] = [] func withEscaping(completion: @escaping () -> Void) { completionHandler.append(completion) } func withoutEscaping(completion: () -> Void) { completion() } }
MyClass의 내부함수 withEscaping의 completion 클로저가 completionHandler 배열에 저장이 된다.
여기서 "이쉒 뭐라는겨" 라는 생각이 드신다면 일급함수에 대해서 먼저 공부하는 것이 좋다.
아무튼
let myclass = MyClass() myclass.callFunc() print(myclass.x) // 200 myclass.completionHandlers.first?() print(myclass.x) // 100
MyClass의 인스턴스를 생성하고 callFunc 메서드를 실행한다면 withEscaping과 withoutEscaping 메서드가 실행이 되고 x의 값은 200으로 바뀌게 된다. 그 이유는 withEscaping의 클로저가 바로 호출되는 것이 아니라 completionHandler 배열에 저장이 되기 때문이다. 그래서 아래에 myclass.completionHandlers.first?()을 실행을 하고 나서야 첫번째 원소로 있는 탈출 클로저가 호출이 되어 self.x = 100 로직이 실행이 되게 된다.
참고
https://www.youtube.com/watch?v=xiS5gJOIQxI
Apple Inc. The Swift Programming Language (Swift 3.1) - Escaping Closure
https://hcn1519.github.io/articles/2017-09/swift_escaping_closure
Completion handlers in Swift 3.0
What do mean @escaping and @nonescaping closures in Swift?
728x90'ios > Etc' 카테고리의 다른 글
Xcode 기능들과 AppProject 속성 (0) 2022.05.19 Info.plist (0) 2022.05.18 Concurrency & Threading (0) 2022.04.08 Swift 메모리 관리: ARC (0) 2022.03.22 GoF Design Pattern (0) 2022.03.06