클로저를 다른 함수의 인자값으로 전달할 때엔 가독성을 해치는 복잡한 구문이 만들어질 수 있다. 이와 같이 말이다.
value.sort(by: { (s1, s2) in
return s1 > s2
})
그래서 스위프트는 인자값으로 클로저를 전달하는 상황에서 문법을 변형할 수 있도록 지원는 문법이 있는데, 바로 트레일링 클로저 문법이다. 트레일링 클로저(Trailing Closure)는 함수의 마지막 인자값이 클로저일 때, 이를 인자값 형식으로 작성하는 대신 함수의 뒤에 꼬리처럼 붙일 수 있는 문법을 의미한다. 이 때 인자레이블은 생략되고 이 문법은 함수의 마지막 인자값에만 적용이된다는 특징이 있다. 실제 적용한 예를 살펴보자.
value.sort() { (s1, s2) in
return s1 > s2
}
인자값으로 사용되던 클로저가 통째로 빠져나와 sort( )메소드의 뒤쪽에 붙은 것을 확인할 수 있다. 꼬리처럼 말이다. 이로 인해 코딩 과정에서 sort( ) 함수를 열고 닫는 범위가 줄어들게된다. 때문에 괄호 누락의 실수나 괄호를 계속 닫아줘야한다는 부담감??? 등의 불편함을 해소할 수 있다.
스위프트에서 함수의 마지막 인자값이 클로저일 때 트레일링 클로저 문법을 사용하는 것이 일반화되어 있다. 여기서 인자값이 하나일 경우, 조금 더 변화가 가능하다. 다음 구문을 살펴보자.
value.sort { (s1, s2) in
return s1 > s2
}
sort 메소드 뒤의 괄호가 사라진 것을 확인할 수 있다. 더 필요한 인자값이 없고, 트레일링 클로저 문법 덕분에 호출 구문이라는 점을 명확히 할 수 있으므로 괄호를 굳이 쓸 필요가 없는 것이다. 때문에 인자값이 하나일 경우 마지막 인자값 뿐만 아니라 인자값을 넣어주기 위한 괄호 부분도 생략이 가능하다.
만약 인자값이 여러 개라면 괄호를 무작정 삭제하면 안된다. 다음 예제를 보자.
func divide(base: Int, success s : () -> Void) -> Int {
defer {
s() // 성공함수 실행
}
return 100 / base
}
이 함수는 두 개의 인자값을 입력받는데, 첫번째는 Int 타입의 값이고, 두 번째는 연산 성공시 실행할 함수 or 클로저이다. 마지막 인자값에 클로저를 넣을 수 있으므로 위 함수는 트레일링 클로저를 사용할 수 있는 조건이 충족된다. 트레일링 클로저를 사용해 호출하는 구문은 다음과 같다.
divide(base: 100) { () in
print("연산에 성공했습니다.")
}
divide 함수는 첫번째 인자값으로 Int 타입의 정수를 입력받아야 하므로, 괄호를 완전히 생략할 수는 없다. 대신 두 번째 인자값에 대한 레이블인 "success:"는 생략 가능하기에 어쩌면 "base:"라는 인자 레이블 하나만 가지는 함수처럼 보이기도 한다. 어쨌든 우리가 기억할 것은 인자값이 하나 이상이라면 괄호를 생략할 수 없다는 점이다.
마지막 인자값들이 모두 클로저라면 트레일링 클로저를 연이어 사용할 수 있을까?
'마지막 인자값이 클로저일 때'라는 조건 때문에 연이어 두 개의 클로저 인자값이 사용될 경우 트레일링 클로저도 연이어 적용이 가능하지 않을까 기대해볼 수도 있다. 하지만 그렇지 않다. divde 함수를 다음과 같이 변경했다고 가정해보자.
func divide(base: Int, success s: () -> Void, fail f: () -> Void) -> Int {
guard base != 0 else {
f() // 실패 함수 실행
return 0
}
defer {
s() // 성공 함수 실행
}
return 100 / base
}
divide 함수에 함수 타입의 매개변수를 하나 더 추가하였다. 실패했을 때 실행될 구문이다. 덕분에 마지막 두개의 인자값은 모두 함수 타입이지만, 트레일링 클로저 문법은 마지막 인자값에만 적용할 수 있기 때문에 호출시 두 번째 인자값인 success 부분은 다음과 같이 클로저를 직접 인자값으로 넣어주어야 한다.
// 마지막 fail 부분만 트레일링 클로저로 사용됨
divide(base: 100, success: { () in
print("연산이 성공했습니다.")
}) { () in
print("연산에 실패했습니다")
}
// 이렇게 하는건 안 됨!!!
divide (base: 100) { () in
print("연산에 성공했습니다.")
} { () in
print("연산에 실패했습니다")
}
출처 : 꼼꼼한 재은씨의 Swift 문법편
'Swift > 문법' 카테고리의 다른 글
스위프트(Swift) - 구조체와 클래스 Ⅰ. 기본 개념 (0) | 2022.05.31 |
---|---|
스위프트(Swift) - 함수(Fuction) Ⅹ. @escaping, @autoescape (0) | 2022.05.26 |
스위프트(Swift) - 함수(Function) Ⅷ. 클로저(Closure) (0) | 2022.05.24 |
스위프트(Swift) - 함수(Function) Ⅶ. 함수의 중첩 (0) | 2022.05.23 |
스위프트(Swift) - 함수(Function) Ⅵ. 일급 함수의 특성 (0) | 2022.05.19 |