티스토리 뷰
Swift Docs > Closures > Autoclosures 를 바탕으로 하고 있습니다.
# Autoclosure 란
autoclosure는 함수에 argument로 전달되는 expression 을 감싸기 위해 자동으로 만들어지는 클로저 입니다.
(An autoclosure is a closure that’s automatically created to wrap an expression that’s being passed as an argument to a function)
1) autoclosure 를 전달받고 싶으면, 파라미터 타입을 @autoclosure attribute 로 marking 하면 됩니다.
2) autoclosure는 argument 를 가지지 않으며 리턴값이 있어야합니다.
3) 이런 syntactic convenience 는 함수 parameter에 중괄호를 쓰는 것을 생략할 수 있게 해줍니다.
4) autoclosure는 evaluation 을 delay 할 수 있게 해줍니다. (closure를 콜하기 전 까지 코드가 실행되지 않게 해줌)
Delaying evaluation 은 코드가 side effect 가 있거나 계산 비용이 많이 드는 경우 유용합니다.
# Autoclosure 예제 (1)
예를들어 assert(condition:message:file:line:) function은 condition, message 파라미터로 autoclosure를 받습니다.
1) 파라미터 타입이 @autoclosure 로 마킹된 것을 볼 수 있습니다.
2) autoclosure는 argument를 가지지 않으며 리턴값이 있는 것을 볼 수 있습니다.
3)
assert문을 쓸 때 이렇게 안쓰고
assert({ a == b }, { "에러 발생" })
괄호를 생략해서 사용하고 있습니다.
assert(a == b, "에러 발생")
autoclosure이기 때문에 저희가 expression을 넘겨주면
자동으로 expression을 감싼 클로저로 컨버팅 될 것입니다.
4)
condition parameter는 오직 debug build 일 때만 평가되며
message parameter는 오직 condition이 false 일때만 평가됩니다.
(문서에서는 evaluated 라는 단어를 사용하고 있는데, 불리는 지 안불리는 지로 생각하시면 될 것 같아요)
# Autoclosure 예제 (2)
@autoclosure what, why and when 글을 보면 autoclousre를 잘 활용한 예제가 나옵니다!
(아래 예제는 모두 이 글에서 가져왔습니다)
우선 이런 간단한 함수가 있다고 해볼게요!
morning 값을 보고 true일 때만 굿모닝을 해주고 있습니다.
func goodMorning(morning: Bool, whom: String) {
if morning {
print("Good morning, \(whom)")
}
}
goodMorning(morning: true, whom: "Pavel")
goodMorning(morning: false, whom: "John")
// 출력결과
// Good morning, Pavel
이제 name 관련 코드를 이런 식으로 확장해볼게요!
giveAname 함수는 간단하게 구현되어있지만 랜덤으로 name을 리턴해준다는 등 복잡한 로직으로 대체될 수 있겠죠?!
우선 morning이 true일 때는 기존처럼 잘 동작합니다.
func goodMorning(morning: Bool, whom: String) {
if morning {
print("Good morning, \(whom)")
}
}
func giveAname() -> String {
print("giveAname() is called")
return "Robert"
}
goodMorning(morning: true, whom: giveAname())
// 출력결과
giveAname() is called
Good morning, Robert
하지만 false 일 때는 기존과 동작이 달라졌죠..? (false일 때는 whom을 평가안했는데 하게 바뀜. 즉 delaying evaluation이 안되고 있음)
goodMorning(morning: false, whom: giveAname())
// 출력결과
giveAname() is called
그래서 morning이 false일 때, giveAname 이 평가 안되게 하고 싶으니까 whom을 클로저 타입으로 바꾸게 됩니다.
func goodMorning(morning: Bool, whom: () -> String) {
if morning {
print("Good morning, \(whom())")
}
}
func giveAname() -> String {
print("giveAname() is called")
return "Robert"
}
goodMorning(morning: true, whom: giveAname)
// 출력결과
giveAname() is called
Good morning, Robert
goodMorning(morning: false, whom: giveAname)
// 출력결과 없음
하지만 이렇게 바꾸면 맨 처음 예제처럼 String 값을 넘겨줄 수가 없게 됩니다...
이럴 때 autoclosure를 사용하면 모든 경우를 대응할 수 있게 됩니다. 🎉
func goodMorning(morning: Bool, whom: @autoclosure () -> String) {
if morning {
print("Good morning, \(whom())")
}
}
func giveAname() -> String {
print("giveAname() is called")
return "Robert"
}
goodMorning(morning: false, whom: giveAname())
goodMorning(morning: true, whom: "Pavel")
// 출력결과
Good morning, Pavel
정리해보면
"autoclousre를 사용해서 값을 직접 받거나 함수가 리턴해주는 값을 받을 수 있으며
모든 경우 delaying evaluation이 가능하다. "
앞서 살펴본 assert문도 위와 동일한 니즈로 autoclosure를 사용했을 것 같네요!
assert(a == b, "에러 발생")
assert(condition(), message())
# 그외
1)
autoclosure를 과도하게 사용하면 코드를 이해하기 어려울 수 있습니다.
context 또는 function name을 통해 평가가 delay 될 수 있음을 명확하게 해야합니다.
2)
autoclosure가 escape 되도록 하고 싶으면 @autoclosure 와 @escaping 를 둘다 사용해주면 됩니다.
func collectCustomerProviders(_ customerProvider: @autoclosure @escaping () -> String) {
...
}
순서는 상관없습니다.
참고로 Alamofire 는 @escaping @autoclosure 순서로 사용해주고 있더라구요!
'🍏 > Swift' 카테고리의 다른 글
[Swift] Structure > custom initializer를 추가해도 default, memberwise initializer 를 유지하는 방법 (0) | 2022.01.08 |
---|---|
[Swift] Property Wrapper (0) | 2022.01.06 |
[Swift] 함수 관련 혼용되는 용어 정리 (parameter name, argument label, argument value) (0) | 2021.12.26 |
[Swift] Concurrency (2) | 2021.12.14 |
[Swift] Strings and Characters > Unicode (0) | 2021.12.12 |
- Total
- Today
- Yesterday
- Django Firebase Cloud Messaging
- PencilKit
- Flutter getter setter
- 장고 Custom Management Command
- SerializerMethodField
- flutter 앱 출시
- DRF APIException
- flutter deep link
- Sketch 누끼
- Django Heroku Scheduler
- METAL
- drf custom error
- flutter dynamic link
- Flutter Spacer
- cocoapod
- Watch App for iOS App vs Watch App
- flutter build mode
- 구글 Geocoding API
- ipad multitasking
- Flutter 로딩
- Dart Factory
- Flutter Text Gradient
- 플러터 얼럿
- 플러터 싱글톤
- Python Type Hint
- ribs
- Flutter Clipboard
- 장고 URL querystring
- Django FCM
- github actions
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |