- 내부 함수와 내부 함수에 영향을 미치는 주변 환경을 모두 포함한 객체
- 클로저는 정의된 컨텍스트에서 모든 상수와 변수에 대한 참조를 캡처하고 저장할 수 있다. 이러한 상수와 변수를 폐쇄라고 한다.
- Swift는 캡쳐의 모든 메모리 관리를 처리한다.
- 클로저는 Named Closuer와 Unnamed Closure로 나뉘는데, Named Closure은 우리가 흔히 함수로 부르고, 우리가 보통 Closure을 말하면 그것은 익명함수 즉 Unnamed Closure을 의미한다.
완전한 선언과 이름없이 함수와 유사한 구조의 짧은 버전을 작성하는 것이 때때로 유용하며, 특히 함수를 하나 이상의 인자로 사용하는 함수 또는 메서드로 작업할 때가 필요하다! 그럼 의미에서 클로저 표현식은 명확성이나 의도를 잃지 않고 짧은 형태로 클로저를 작성 하기위한 몇가지 구문 최적화를 제공해준다.
func doSomething() {
var message = "HI I am HIDI"
// 클로저 범위 시작
var num = 10
let closure = {print(num)}
// 클로저 범위 끝
print(message)
클로저 내부에서 외부 변수인 nu이라는 변수를 사용(print)하기 때문에 num의 값을 클로저 내부적으로 저장하고 있는데, 이것을 클로저에 의해 num의 값이 캡쳐 되었다라고 표현한다.
message란 변수는 클로저 내부에서 사용하지 않기 때문에 클로저에 의해 값이 캡쳐되지 않은것이다!
익명 함수인 만큼 func란 키워드를 쓰지 않는다!
클로저 헤더 + 'in' + 클로저 바디로 구성되어 있다.
클로저 사용법을 통해 클로저식 데이터형을 선언할 수 있다!
{(Parameters) -> Return Type in // 클로저 헤더 + in
실행구문 // 클로저 바디
}
ex)
var sum: (Int, Int) -> Int = { (a: Int, b: Int) -> Int in
return a + b
}
/*
i) var sum: (Int, Int) -> Int : Int형 2개를 받아 Int 하나를 반환하는 형이야~
라고 말해주는 부분 (클로저식 타입 표현)
ii) { (a: Int, b: Int) -> Int in return a + b } : 나는 Int형 변수 2개를 받고,
Int를 반환하는 클로저야!
*/
let closure = {() -> () in
print("Closure")
}
주의할점!!!
클로저에는 Argument Label(전달인자 레이블)이 없다!!!!
let closure = { (name: String) -> String in
return "Hello, \(name)"
}
closure("hidi") // "Hello, hidi"
closuer(name: "hidi") // error why? 클로저에는 전달인자 레이블이 없기 때문에!
클로저는 일급 객체임으로, 일급객체의 특성을 다 가지고 있다. (실질적인 매개변수, 반환값, 할당의 대상, 비교연산 등등)
클로저는 변수나 상수에 대입할 수 있고, 이 대입된 변수나 상수로 실행도 할 수 있는데
i)처럼 대입과 동시에 클로저를 작성할 수도 있고
ii)처럼 새로운 변수나 상수에 대입할 수도 있다!
//i)
let closure = {() -> () in
print("Closure")
}
//ii)
let closure2 = closure
i)은 함수를 파라미터로 전달받는 함수로, 파라미터로 함수를 넘겨줘도 되지만!
ii)처럼 클로저를 넘겨줘도 된다! 즉 doSomething 함수의 hello란 Argument Label의 Parameter로 전달된것이다!
// i)
func doSomething(closure: () -> ()) {
closure()
}
// ii)
doSomething(hello: { () -> () in
print("Hello!")
}
i)처럼 실제값을 return할 때 함수가 아닌 클로저로 리턴할 수 있다.
또한 ii)처럼 호출하는 곳에서 클로저를 받아서 실행과 할당도 가능하다!
// i)
func doSomething () -> () -> {
return { () -> () in
print("Hello hidi!"
}
}
// ii)
let closure = doSomething()
closure()
클로저가 대입된 상수 closure를 호출 구문인 ()를 이용해서 실행시킬 수 있음!
let closure = { () -> String in
return "Hello hidi"
}
closure()
클로저를 변수나 상수에 대입하지 않고 실행하고 싶다면, (완벽한 일회성!!)
그때 ㄴ클로저를 () 소괄호로 감싸고, 마지막에 호출 구문인 ()를 추가해주면 된다!
({ () -> () in
print("Hello hidi")
})()