클로저(Closure)란 내부 함수와 내부 함수에 영향을 미치는 주변 환경을 모두 포함한 객체
클로저(Closure)는 Named Closure & Unnamed Closure 둘 다 포함하지만, 보통 Unnamed Closure(익명함수)를 말함
func doSomething(){
print("abd")
}
let closure = { print("abc")}
{ (Parameters) -> Return Type in //Closure Head, Head 와 Body를 in으로 구분 지어줌
실행구문 // Closure body
}
let closure = { () -> () in //1급 객체라 상수에 대입 가능
print("Closure")
}
let closure = { (name: String) -> String in
return "Hello, \(name)"
}
closure("abc")
closure(name: "abc")//에러 (Argument Label을 사용하지 않음)
1. 클로저를 변수나 상수에 대입할 수 있다
let closure = { () -> () in
print("closure")
}
let closure2 = closure
2. 함수의 파라미터 타입으로 클로저를 전달할 수 있다
func doSomething(parameter: () -> ()){ //함수를 파라미터로 전달받는 함수
closure()
}
doSomething(parameter: { () -> () in //클로저를 파라미터로 넘김
print("closure")
})
3. 함수의 반환 타입으로 클로저를 사용할 수 있다
//기존 선언부는 기존 함수와 동일
func doSomething() -> () -> (){
}
//실제 값을 리턴할때 함수가 아닌 클로저 리턴 가능
func doSomething() -> () -> () {
return { () -> () in
print("Hello")
}
}
let closure = doSomething()
closure()
let closure = { () -> String in
return "Hello"
}
closure()
({ () -> () in
print("Hello")
})()
함수의 마지막 파라미터가 클로저일 때, 이를 파라미터 값 형식이 아닌 함수 뒤에 붙여 작성하는 문법. 이때, Argument Label은 생략된다
func doSomething(closure: () -> ()){
closure()
}
//일반적인 호출법(Inline Closure)
doSomething(closure : { () -> () in
print("Hello")
})
//트레일링 클로저
doSomething () { () -> () in
print("Hello")
}
doSomething { () -> () in
print("Hello")
}
func fetchData(success: () -> (), fail: () -> ()){
//do something...
}
//Inline Closure
fetchData(success: { () -> () in
print("success")
}, fail: { () -> () in
print("fail")
})
//트레일링 클로저
fetchData(success: { () -> () in
print("success")
}) { () -> () in
print("fail")
}
문법을 최적화 하여 클로저를 단순하게 쓸 수 있게 하는 것
func doSomething(closure: (Int, Int, Int) -> Int) {
closure(1, 2, 3)
}
//기본 형식
doSomething(closure: { (a: Int, b: Int, c: Int) -> Int in
return a + b + c
})
doSomething(closure: { (a, b, c) in
return a + b + c
})
$0, $1, $2식으로 $과 index를 이용해서 Parameter에 순서대로 접근 하는 것doSomething(closure: {
return $0 + $1 + $2
})
doSomething(closure: {
return $0 + $1 + $2
})
doSomething(closure: {
$0 + $1 + $2
})
doSomething(closure: {
print("\($0),\($1),\($2)")
$0 + $1 + $2 //단일 리턴문이 아니라 에러
})
doSomething(){
$0 + $1 + $2
}
doSomething{
$0 + $1 + $2
}
@autoclosure란 파라미터로 전달된 일반 구문 & 함수를 클로저로 래핑 하는 것
func doSomething(closure: @autoclosure () -> ()) {
}
func doSomething(closure: @autoclosure () -> ()) {
closure()
}
doSomething(closure: 1>2) // 1>2는 클로저가 아닌 일반구문이지만 사용가능
일반 구문은 작성되자마자 실행되어야 하지만 autoclosure로 작성할 경우 함수 내에서 글로저를 실행할 때까지 구문이 실행 되지 않음
^^^^ 까지는 non-escaping Closure ^^^^
non-escaping Closure과 다르게 함수 실행을 벗어나서 함수가 끝난 후에도 클로저를 실행하거나, 중첩함수에서 실행 후 중첩 함수를 리턴하고 싶거나, 변수 상수에 대입하고 싶은 경우 사용
func doSomething(closure: @escaping () -> ()) {
}
func doSomething(closure: @excaping () -> ()) {
let f: () -> () = closure // 변수나 상수에 파라미터로 받은 클로저 대입가능
}
// 함수가 종료된 후에도 클로저 실행 가능
func doSomething(closure: @excaping () -> ()) {
print("function start")
DispatchQueue.main.asyncAfter(dedline: .now()+10){
closure()
}
print("function end")
}
doSomething( print("closure")
func doSomething() {
var message = "Hello"
//클로저 범위 시작
var num = 10
let closure = { print(num) }
//클로저 범위 끝
print(message)
}
closure란 익명 함수는, 클로저 내부에서 외부 변수인 num이라는 변수를 사용(print)하기 때문에 num의 값을 클로저 내부적으로 저장하고 있는데, 이것을 클로저에 의해 num의 값이 캡쳐 되었다 라고 표현
message란 변수는 클로저 내부에서 사용하지 않기 때문에 클로저에 의해 값이 캡쳐되지 않음
Closure는 값을 캡쳐할 때 Value/Reference 타입에 관계없이 Reference Capture 한다
func doSomething() {
var num: Int = 0
print("num check #1 = \(num)") //0
let closure = {
print("num check #3 = \(num)")
}
num = 20
print("num check #2 = \(num)") // 20
closure() // 20
}
func doSomething() {
var num: Int = 0
print("num check #1 = \(num)") // 0
let closure = {
num = 20
print("num check #3 = \(num)")
}
closure() // 20
print("num check #2 = \(num)") // 20
}
클로저의 시작인 { 의 바로 옆에 []를 이용해 캡쳐할 멤버를 나열한다. 이때 in 키워드도 꼭 함께 작성한다
let closure = {[num1, num2]} in
Capture Lists를 사용하면 가능
func doSomething() {
var num: Int = 0
print("num check #1 = \(num)") //0
let closure = { [num] in
print("num check #3 = \(num)")
}
num = 20
print("num check #2 = \(num)") // 20
closure() // 0
}
참조
개발자 소들이