→ 코드 최대한 단순하게 축약
1) 파라미터와 리턴형 생략 가능
2) 파라미터 name 은 short-hand argument 이름(= $0
) 으로 대치 (파라미터 이름과 in keyword 지움)
3) 단일 리턴문인경우 리턴 키워드 생략 (implicit return)
4) 파라미터가 마지막 파라미터라면 (trailing closure)
5) 파라미터 없으면 괄호 생략
var pro = products.filter({ (name: String) -> Bool in
return name.contains("pro")
})
==
products.filter({
$0.contains("Pro")
})
/*trailing closure */
products.filter () {
$0.contains("Pro") //argument label만 남아있으면 지워도 됨
}
-- () 생략
products.filter {
$0.contains("Pro") //argument label만 남아있으면 지워도 됨
}
→ nested function 은 값을 캡쳐함
"값을 캡쳐한다" : 값을 가져와서 쓴다. (복사본 캡쳐(objc) / 참조캡쳐, 원본그대로 가져옴(swift))
원본 값이 사라져도 클로저의 body 안 에서 그 값을 활용
var num = 0
let c = { print("#1: \(num)") } // closure 외부의 값에 접근, capture
c()
num += 1
print("#2: \(num)")
>> #1: 0
>> #2: 1
--- 내부에서 값 바꾸면 외부값도 바뀜---
var num = 0
let c = { num+=1 print("#1: \(num)") }
c()
print("#2: \(num)")
>> #1: 1
>> #2: 1 (objc 에서는 0이 출력됨)
--- 하나의 클로저, 2개 할당 & 서로 다른 클로저 ---
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0
func incrementer() -> Int {
runningTotal += amount
return runningTotal
}
return incrementer
}
let plusTen = makeIncrementer(forIncrement: 10)
let plusSeven = makeIncrementer(forIncrement: 7)
// 함수가 각기 실행되어도 실제로는 변수 runnigTotal과 amount가 캡쳐되서 그 변수를 공유하기 때문에 누적된 결과를 가진다.
let plusedTen = plusTen() // 10
let plusedTen2 = plusTen() // 20
// 다른 클로저이기 때문에 고유의 저장소에 runningTotal과 amount를 캡쳐해서 사용한다.
let plusedSeven = plusSeven() // 7
let plusedSeven2 = plusSeven() // 14
클로저가 함수의 인자로 전달되지만 함수 밖에서 실행되는 것(함수가 반환된 후 실행되는 것)
--- unescaping closure ---
func perform(closure: () -> ()) {
print("start")
closure()
print("end")
}
perform {
print("closure")
} // == perform(closure:{ print("hihi") })
>> start
>> closure
>> end
// 함수 body 내에서 호출된 closure 는 항상 함수 실행이 종료되기 전에 실행이 완료됨
// 함수의 실행흐름을 탈출하지 X
--- escaping closure ---
func performEscaping(closure: () -> ()) {
print("start")
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
closure()
} // closure 는 non-escaping 이기 때문에 에러남
}
== fix!
func performEscaping(closure: @escaping () -> ()) {
print("start")
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
closure()
}
print("end")
}
performEscaping {
print("closure")
}
>> start
>> end
>> closure ( 3초뒤 )