Closure Head
와 Closure Body
를 가지고 있고, in을 통해서 구분한다.closure는 함수이름이 없는 익명이지만, 익명 함수이다.
1급 객체의 특성을 살려서 상수/변수에 클로저를 대입할 수 있다.
let hello = { () -> () in
print("Hello")
}
hello() // hello
let hello2 = { (name: String) -> String in
return "Hello, \(name)"
}
parameter Name이 단독으로 쓰였다고, Arguemnt Label이자 Parameter Label이라고 생각할 수 있겠지만, closure에서는 Argument Label을 사용하지 않는다.
오직 parameter Name만 사용된다.
hello2(name: "장일규") // error
hello2("장일규")
파라미터가 있는 함수를 호출할 때 일반함수 호출하듯이 Argument Label을 적고 파라미터 값을 넘겨주면 에러가 난다.
func doSomething(closure: () -> ()) {
closure()
}
doSomething함수의 parameter로 closure가 정의가 되어있다.
parameter에 우리가 알고 있는 일반적인 함수를 넘길 수도 있지만, 아래 코드와 같이 클로저를 넘길 수 도 있다.
doSomething(closure: { () -> () in
print("closure")
})
func doSomething2() -> (Int) -> () {
return { (age: Int) -> () in
print("I'M \(age)")
}
}
doSomething2()(29)
위와 같이 클로저를 리턴할 수도 있다.
let ageClosure: (Int) -> () = doSomething2()
ageClosure(19)
호출하는 곳에서 클로저를 받아서 실행할 수도 있다.
클로저 표현식을 함수의 최종 인자로 전달해야 하는데 그 클로저 표현식이 아주 길 경우, 이 대신 트레일링 클로저 (trailing closure) 를 작성하는 것이 유용할 수 있다.
'트레일링 클로저’ 는, 여전히 함수의 인자이면서
도, 함수 호출 괄호 뒤에 작성
한다.
func someFunctionThatTakesAClosure(closure: () -> Void) {
closure()
}
위에 someFunctionThatTakesAClosure함수와 같이 클로저 한개만 파라미터로 받는 함수가 있을때 함수를 호출하기 위해서
// 다음은 이 함수를 '트레일링 클로저'를 사용하지 않고 Inline Closure로 호출하는 방법
someFunctionThatTakesAClosure(closure: {
// 클로저 본문은 여기에 둔다.
print("Hello!")
})
위에 코드와 같이 작성했다.
클로저가 파라미터의 값 형식으로 함수 호출되는 인자값 인 괄호()안에 작성되어 있는 것을 Inline Closure라고 한다.
클로저를 파라미터의 값 형식으로 전달하는 것이 아닌 함수의 가장 마지막에 클로저를 꼬리처럼 덧붙여서 사용할 수있다.
파라미터에 클로저 단 한개만 있을 경우에는 이 클로저는 첫 파라미터이자 마지막 파라미터이므로 트레일링 클로저가 가능하다. 또한, 호출 구문인 괄호 ()도 생략할 수 있다.
'closure'라는 ArgumentLabel은 트레일링 클로저에선 생략된다.
// 다음은 이 함수를 트레일링 클로저로 호출하는 방법
someFunctionThatTakesAClosure() { () -> () in
// 끝자리 클로저 본문은 여기에 둡니다.
}
func doSomething2(success: () -> (), fail: () -> ()) {
// 함수 본문
success()
fail()
}
위에 doSomething2함수는 success와 fail 두개의 클로저를 매개변수로 가지고 있는 함수이다.
// 다음은 이 함수를 '트레일링 클로저'를 사용하지 않고 Inline Closure로 호출하는 방법
doSomething2(success: { () -> () in
print("Success!")
}, fail: { () -> () in
print("Fail!")
})
위에 코드는 Inline Closure로 호출하는 코드이다.
doSomething2(success: {
() -> () in
print("Success!")
}){ () -> () in
print("Fail")
}
위에 코드 처럼 마지막 파라미터의 클로저는 함수 뒤에 붙여서 사용할 수 있다.
단, 여러개의 파라미터가 있을 경우에는 함수 호출 괄호()를 생략할 수 없다.
문법을 최적화하여
func doSomething3(closure: (Int,Int,Int) -> Int) {
closure(1,2,3)
}
doSomething3함수는 매개변수로 closure를 받고 있다.
closure에 매개변수로 Int 3개를 받고 있고, Int타입을 반환한다.
doSomething3함수 내부에서는 매개변수로 받은 closure를 실행하는데 closure에 매개변수로 1,2,3을 넘겨준다.
doSomething3(closure: { (a: Int,b: Int,c: Int) -> Int in
return a+b+c
})
위에 호출부는 Inline Closure방식으로 작성한 코드이다.
위에 코드를 아래와 같이 줄일 수 있다.
doSomething3(closure: { (a, b, c) in
return a+b+c
})
상수의 타입인 : Int
와 return(반환)타입인 Int
를 생략하였다.
Shortand Argument Names은 Parameter Name(매개변수 이름) 대신 사용할 수 있는 것이다.
doSomething3(closure: {
return $0 + $1 + $2
})
매개변수 이름 대신
a -> $0
b -> $1
c -> $2
$ 와 접근하고자 하는 index를 나타내는 숫자로 순서대로 접근 할 수 있다.
doSomething3(closure: {
return $0 + $1 + $2
})
위와 같이 코드 내부에 return문 하나만 있을 경우 return 키워드도 생략 할 수 있다.
```swift
doSomething3(closure: {
$0 + $1 + $2
})
return문을 생략한 코드이다.
doSomething3() {
$0 + $1 + $2
}
트레일링 클로저를 활용해 파라미터 마지막이 클로저일 경우 위와 같이 줄일 수 있음
doSomething3 {
$0 + $1 + $2
}