티스토리 뷰
네트워크 요청이나, 비동기 작업할 때 아래와 같은 코드를 본 적이 있을 것이다
func deleteUserProfile(completion: @escaping (Result<Void, Error>) -> Void) -> Void
실제로 엄청 많이 사용되기도 하고, 자주 사용되는 만큼 개념을 잘 알고 사용해야 한다
따라서 @escaping 클로저가 무엇인지에 대해 알아보자!
📚 들어가기 전
escaping closure를 알기 위해선 클로저에 대해서 기본적으로 알고 있어야 한다!
클로저를 다루면서 escaping closure 클로저에 대해 아주 간략하게 포스팅을 해놨었는데 한번 읽어보고 지금 포스팅을 읽으면 더 이해하기 쉬울 것이다.
[iOS/Swift] Closure
이전 포스팅에서는 life cycle에 대해서 알아보았는데 오늘은 스위프트의 클로저에 대해서 알아보겠다! 스터디에서 가져온 질문은 아래와 같으며 답변하고 정리하는 식으로 블로그 포스팅을 진
yanni13.tistory.com
💡 escaping closure
escape(탈출) 말 그대로 함수가 종료된 뒤 실행하는 클로저이다.
보통 비동기 작업을 할 때 클로저를 사용해서 다루곤 한다.
서버에서 받은 값을 성공적으로 가져왔을 때와, 실패했을 때 어떤 동작을 실행할 건지를 다뤄주어야 하기 때문이다.
하지만 함수는 작업이 시작한 후에 실행되며 작업이 완료될 때까지 클로저를 호출하지 않기 때문에 escaping 클로저를 통해서 함수가 종료된 후에 실행할 수 있도록 하는 것이다!
이렇게 말하면 이해가 되지 않을 수도 있으니 코드로 한번 살펴보자!
func orderPizza(completion: @escaping () -> Void) {
print("피자 주문을 받았습니다.")
// 피자 준비 시간을 시뮬레이션 (5초)
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
completion() // 5초 후에 고객에게 연락
}
print("주문 접수가 완료되었습니다.")
}
orderPizza {
print("피자가 준비되었습니다! 찾으러 와주세요.")
}
print("주문 후 다른 일을 합니다.")
위와 같은 코드를 실행시키면 다음과 같은 순서대로 출력이 나온다.
- 피자 주문을 받았습니다
- 주문 접수가 완료되었습니다.
- 주문 후 다른 일을 합니다.
- 피자가 준비되었습니다! 찾으러 와주세요.
즉 orderpizza 함수가 종료되어도 completion클로저가 살아남아 있기 때문에 5초가 지나 나중에 실행될 수 있는 것이다!!!!
이건 아주 간단한 print문의 출력을 확인하기 때문에 입력타입이 존재하지 않고 Void타입을 반환하는 클로저로 completion을 받겠다고 선언했기 때문에 어느 정도 이해를 할 수 있지만 실제 네트워크 통신에서는 조금 더 복잡하게 쓰인다.
func loadProfileImage(from url: String, completion: @escaping (Result<UIImage, Error>) -> Void) {
updateUserProfileUseCase.loadProfileImage(from: url) { [weak self] result in
switch result {
case let .success(image):
DispatchQueue.main.async {
self?.userData.value.imageUpdate(image: image)
completion(.success(image)) // 이미지 로드 성공 시 completion 호출
}
case let .failure(error):
Log.debug("Failed to load image: \(error)")
completion(.failure(error)) // 이미지 로드 실패 시 completion 호출
}
}
}
실제 프로젝트에 적용된 escaping closure를 가져와 보았다.
간단하게 이 함수가 하는 역할을 소개하자면 url 타입으로 이미지를 가져온 후 성공여부에 따라 콜백을 호출하는 구조이다!
(Result<UIImage, Error>)가 어떤 걸 의미하는지 알아보자
공식문서에 들어가 보면 성공과 실패를 나타내는 값이라고 설명되어 있다.
즉 성공했을 때 UIImage타입을 반환해주고, 실패했을 때 error를 반환한다는 뜻이다. 그래서 다시 코드로 살펴보면 switch문을 통해 case로 성공했을때 image타입을 넣어주고 있고, 실패했을때 error 타입을 넣어주고 있다.
📍non-escaping 클로저와의 차이점
@escaping과 non-escaping의 가장 큰 차이는 클로저가 함수의 실행이 끝난 후에도 실행될 수 있느냐의 차이다!
non-escaping클로저는 클로저가 함수 내부에서 실행되어야 하며, 함수 실행이 끝나기 전에 클로저가 호출되어야 한다.
swift에서는 클로저를 사용할 때 기본값으로 non-escaping 클로저로 설정되어 있기 때문에 함수 내부에서 밖에 클로저를 호출하지 못한다.
func orderPizza(completion: () -> Void) {
print("피자 주문을 받았습니다.")
completion()
print("주문 접수가 완료되었습니다.")
}
orderPizza {
print("피자가 준비되었습니다! 찾으러 와주세요.")
}
아까 피자 예제랑 같은 동작을 하는 non-escaping으로 된 예제이다.
completion 클로저를 매개변수로 받아서 orderPizza함수 내부에서만 completion 클로저가 실행되는 것을 확인할 수 있다.
즉, 함수가 종료한 후에는 실행되지 않기 때문에 비동기 처리할 때 non-escaping 클로저를 사용할 수 없다는 것!
비동기를 처리할 수 없기 때문에 escaping예제에 있었던 '피자가 주문 후 다른 일을 합니다'를 none-escaping 예제에서는 반영할 수 없던 것이다~
참고
https://janechoi.tistory.com/6
https://velog.io/@parkgyurim/Swift-escaping-closure
'iOS > Swift' 카테고리의 다른 글
[iOS] @MainActor와 DispatchQueue의 차이 (0) | 2025.03.06 |
---|---|
[iOS] lazy var에 대해 알아보기 (0) | 2024.09.21 |
[iOS/Swift] Closure (0) | 2024.05.08 |
[swiftUI] NSPredicate (0) | 2024.03.30 |
[Swift] Optional (1) | 2024.03.28 |
- Total
- Today
- Yesterday
- MainActor
- swiftUI
- 병합충돌
- 16173
- CustomCalendar
- 가장가까운같은글자
- ios
- Xcode
- 프로그래머스
- Fastlane
- pbxproj
- ScrollViewReader
- XCTest
- securefield
- rxswift
- mlmodel
- closure
- 백준
- combine
- LazyVGrid
- UIKit
- 스위프트
- SWIFT
- ObservableObject
- CoreData
- 코딩테스트
- imagepicker
- 클로저
- 둘만의 암호
- mergeconflict
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |