SwiftUI를 이용해서 코딩을 하다보면, 종종 @escaping 이라는 키워드를 만나게 됩니다.
기본적인 형태는 이렇습니다.
func functionWithEscaping(completion: @escaping () -> Void) {
completion()
}
우리가 흔히 Escaping이라는 단어를 들으면, 어딘가로 탈출하는 모습이 그려지죠?
실제로 Escaping Closure는 해당 로직 밖에서 사용이 가능합니다. 즉, 현재 있는 함수 외부 다른 곳에서 호출이 가능하게 됩니다.
예시를 들어볼까요?
이렇게 () -> Void 형태의 함수를 저장하는 배열이 있다고 할게요.
var completionHandlers: [() -> Void] = []
이 배열에, 원하는 함수를 인자로 받아서 append 해주는 로직을 한번 만들어봅시다.
func storeFunction(completion: () -> Void) {
completionHandlers.append(completion)
}
자 이렇게, 저 배열 변수에 completion이라는 함수를 인자로 받아서 저장해주는 storeFunction이라는 함수를 만들었습니다.
하지만, 그냥 저장해주면 될 것 같았던 코드에 다음과 같은 에러가 발생하게 됩니다.
인자인 completion이 non-escaping 형태이기 때문에, 일반적인 변수로 바꾼다면 아마 문제없을거야~ 라는 뜻인데요.
실제로
var completionHandlers: [Int] = []
func storeFunction(completion: Int) {
completionHandlers.append(completion)
}
다음과 같이 Int를 가지고 하면, 아무런 문제 없이 작동합니다.
하지만... 우리는 지금 함수를 저장하고 싶은거죠??
다르게 말하면,
일반적인 변수는 가능하지만, 함수는 escaping이 불가능하다!
즉 함수가 외부에 저장되어서 사용되는 것은 불가능하다! 라는 것을 역으로 추론할 수 있습니다.
실제로, 클로저(함수)는 기본적으로 non-escaping 이기 때문에, 반드시 호출한 위치에서 실행되고 종료되어야 합니다.
하지만, 다음과 같이 escaping 클로저로 만들어주게 되면, 호출한 위치를 넘어서서 밖에서 저장되고 실행될 수 있게 됩니다.
즉, 외부로 탈출이 가능한거죠!
var completionHandlers: [() -> Void] = []
func storeFunction(completion: @escaping () -> Void) {
completionHandlers.append(completion)
}
자, 그래 그럼 탈출이 가능한건 알았어... 그럼 이렇게 클로저를 탈출시켜서 좋은 점이 뭐야??
가장 흔하게 사용되는 예시로는, 대표적인 비동기 처리인 HTTP 요청 처리가 있습니다.
먼저 코드를 볼까요?
func makeRequest(_ completion: @escaping (Result<(Data, URLResponse), Error>) -> Void) {
URLSession.shared.dataTask(with: URL(string: "https://github.com/")!) { data, response, error in
if let error = error {
completion(.failure(error))
} else if let data = data, let response = response {
completion(.success((data, response)))
}
}
}
completion이라는 클로저는, 언제 실행될지 알 수가 없습니다.
Request를 보내고 나서, 언제 어떤 Response가 도착해서 completion 클로저가 실행될지 알 수 없기 때문이죠.
아예 도착하지 않아서 실행되지 않을 수도 있고요!
즉 escpaing 클로저인 completion은 makeRequest 함수 밖에서 비동기적으로 실행될 수 있는거에요!
'iOS 개발 > SwiftUI' 카테고리의 다른 글
[SwiftUI] inout은 어떻게 작동하는가 (C언어의 Call by Reference와 비교) (0) | 2022.03.21 |
---|---|
[SwiftUI] Generics 타입 제약 (Type Constraints) 다루기 (0) | 2022.03.20 |
[SwiftUI] ForEach에서 \.self를 사용하는 이유와 id 중복 문제 해결 방법 (0) | 2022.03.13 |
[SwiftUI] json parsing 방법 (0) | 2022.03.10 |
[SwiftUI] View 가독성을 늘리는 3가지 방법 (View 쪼개기) (0) | 2022.03.10 |
[SwiftUI] View protocol과 body 변수에 대한 고찰 (some 키워드를 사용하는 이유) (0) | 2022.02.25 |
[Swift UI] @State에 대한 아주 얕은 고찰 (0) | 2021.11.07 |
[SwiftUI] Swift UI에 대한 첫인상 (2) | 2021.11.07 |