티스토리 뷰
지난 클로저에는 값 캡처, 클로저 표현식 에 대해 알아봤는데요!
오늘은 클로저의 심화 과정인
Escaping 클로저
Auto 클로저
에 대해 정리해 보려고합니다!
탈출 클로저 (Escaping Closures)
간단하게 표현하면, 함수가 끝나고 실행되는 클로저 이며, 비동기 작업을 하기 위해 사용합니다.
클로저를 함수의 파라미터로 넣을 수 있는데, 이때 파라미터 타입 앞에 @escaping 을 적어줌으로써 클로저가 escaping 할 수 있게 해줍니다.
var completionHandlers: [() -> Void] = []
func withEscaping(completionHandler: @escaping () -> Void) {
completionHandlers.append(completionHandler)
}
위 함수에서 인자로 전달된 completionHandler 는 someFunctionWithEscapingClosure함수가 끝나고 나중에 처리 됩니다.
이때 @escaping 키워드를 붙여주지 않으면 컴파일 에러가 납니다.
@escaping 클로저를 사용할 때는 self를 명시적으로 사용해야 합니다.
var completionHandlers: [() -> Void] = []
func withEscaping(completionHandler: @escaping () -> Void) {
completionHandlers.append(completionHandler)
}
func noneEscaping(closure: () -> Void) {
closure()
}
class SomeClass {
var x = 10
func doSomething() {
withEscaping { self.x = 100 }
noneEscaping { x = 200 }
}
}
// 1
let instance = SomeClass() // 로직풀이 참고
instance.doSomething()
print(instance.x)
// 2
completionHandlers.first?()
print(instance.x)
로직풀이
가장 상단에 함수 외부에 completionHandlers 변수를 선언하여 빈 배열을 가지는 클로저를 만듭니다.
1번 로직
- let instance = SomeClass() 인스턴스화
- doSomething 호출 하면서 withEscaping, noneEscaping 클로저 실행
- withEscaping 클로저를 completionHandlers 배열에 저장 (저장만 하며 호출되지 않습니다.)
- noneEscaping 클로저가 호출되면서 x 값 200으로 변경
2번 로직
- completionHandlers.first?() 를 호출
- 저장 되어있던 withEscaping 클로저가 호출되며 x값을 100으로 변경
자동 클로저 (Autoclosures)
함수의 인자로 전달되는 코드를 감싸서 자동으로 클로저를 만들어 줍니다.
일단 자동클로저를 사용하면 어떻게 달라지는지 부터 보겠습니다.
둘의 차이점은 중괄호 { } 가 있고 없고의 차이인데 위에가 자동클로저 사용전, 아래가 사용 후 입니다. 좀더 간결해 보이죠?
다시 돌아와서, 자동클로저는 클로저를 실행하기 전까지 실행 되지 않습니다.
아래 예제를 같이 보면서 이해해 보겠습니다.
var customersInLine = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
print(customersInLine.count)
// Prints "5"
// 1
let customerProvider = { customersInLine.remove(at: 0) }
print(customersInLine.count)
// Prints "5"
// 2
print("Now serving \(customerProvider())!")
// Prints "Now serving Chris!"
print(customersInLine.count)
// Prints "4"
1. let customerProvider = { customersInLine.remove(at: 0) } 를 해도
customersInLine 배열의 갯수는 그대로 5입니다.
2. print("Now serving \(customerProvider())!") 여기서 customerProvider()를 호출하니
그제서야 배열의 갯수가 4로 줄어들죠.
이번에는 클로저를 함수의 인자 값으로 넣는 예제를 보겠습니다.
// customersInLine = ["Alex", "Ewa", "Barry", "Daniella"]
func serve(customer customerProvider: () -> String) {
print("Now serving \(customerProvider())!")
}
serve(customer: { customersInLine.remove(at: 0) })
// Now serving Alex!
print(customersInLine.count)
// customersInLine.count: 3
serve() 함수는 인자로 () -> String을 반환하는 클로저를 받는 함수 입니다.
함수를 호출할 때는 아래 두가지로 표현할 수 있습니다.
serve(customer: { customersInLine.remove(at: 0)})
serve { customersInLine.remove(at: 0) }
아까 자동클로저 시작 부분에서 봤던 모양이죠?
이제 @autoclosure 키워드를 사용해 위의 코드를 좀더 간결하게 표현해 보겠습니다.
// customersInLine is ["Ewa", "Barry", "Daniella"]
func serve(customer customerProvider: @autoclosure () -> String) { // @autoclosure 사용
print("Now serving \(customerProvider())!")
}
serve(customer: customersInLine.remove(at: 0))
// Now serving Ewa!
@autoclosure 키워드를 사용함으로써, 인자 값은 자동으로 클로저로 변환이 되어 중괄호 { } 를 생략하고 사용할 수 있습니다.
NOTE
자동클로저를 너무 많이 사용하면 코드를 이해하기 어려울수 있으니,
문맥과 함수이름이을 autoclosure와 연관있음을 명시해야 합니다.
자동클로저(@autoclosure)는 탈출클로저(@escaping)와 같이 사용할 수 있습니다.
// customersInLine = ["Barry", "Daniella"]
// 클로저를 저장하는 배열 선언
var customerProviders: [() -> String] = []
// (클로저)customerProvider를 인자로 받아
func collectCustomerProviders(_ customerProvider: @autoclosure @escaping () -> String) {
// customerProviders 배열에 추가
customerProviders.append(customerProvider)
}
// 클로저를 customerProviders 배열에 추가
collectCustomerProviders(customersInLine.remove(at: 0)) // autoclosure를 사용함으로써 중괄호{ } 생략
// 클로저를 customerProviders 배열에 추가
collectCustomerProviders(customersInLine.remove(at: 0))
print("Collected \(customerProviders.count) closures.")
// Prints "Collected 2 closures."
for customerProvider in customerProviders {
print("Now serving \(customerProvider())!")
}
// Prints "Now serving Barry!"
// Prints "Now serving Daniella!"
autoclosure를 사용하지 않았다면 이렇게 사용할 수 있습니다.
func collectCustomerProviders(_ customerProvider: @escaping () -> String) {
customerProviders.append(customerProvider)
}
collectCustomerProviders { customersInLine.remove(at: 0) }
// 또는
collectCustomerProviders( {customersInLine.remove(at: 0) })
'iOS' 카테고리의 다른 글
[Swift] 열거형 (Enumerations) (0) | 2022.02.09 |
---|---|
[iOS] CocoaPods 설치 및 실행 (0) | 2022.02.06 |
[Swift] 클로저 (Closure) (1) (0) | 2022.01.30 |
ModerRIBs_tutorial 2 - 2 (0) | 2022.01.26 |
ModernRIBs_tutorial2 - 1 (0) | 2022.01.23 |
- Total
- Today
- Yesterday
- Swift 내림차순
- swift protocol
- Swift RIBs
- Swift init
- Swift Leetcode
- 원티드 프리온보딩
- swift 고차함수
- Swift 프로그래머스
- Swift ModernRIBs
- swift reduce
- Swift Error Handling
- RTCCameraVideoCapturer
- Swift joined
- iOS error
- Swift 알고리즘
- Swift
- swift programmers
- swift (programmers)
- swift property
- Class
- Swift final
- removeLast()
- CS 네트워크
- RIBs tutorial
- Combine: Asynchronous Programming with Swift
- ios
- Swift inout
- Swift 프로퍼티
- 2023년 회고
- Swift joined()
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |