함수는 클로저의 한 형태이다!
클로저는 변수나 상수가 선언된 위치에서 reference를 capture하고 저장할 수 있음
Closures are self-contained blocks of functionality that can be passed around and used in your code. Closures can capture and store references to any constants and variables from the context in which they’re defined. This is known as closing over those constants and variables. Swift handles all of the memory management of capturing for you.
Global functions are closures that have a name and don’t capture any values.
Nested functions are closures that have a name and can capture values from their enclosing function.
Closure expressions are unnamed closures written in a lightweight syntax that can capture values from their surrounding context.
Inferring parameter and return value types from context
Implicit returns from single-expression closures
Shorthand argument names
Trailing closure syntax
let names: [String] = ["Sunny", "Kangkyung", "Yun"]
func backwards(first: String, second: String) -> Bool {
return first > second
}
let reversed: [String] = names.sorted(by: backwards)
print(reversed)
// print ["Yun", "Sunny", "Kangkyung"]
// 알파벳 역순으로 정렬된 것을 알 수 있음
클로저 표현은 통상 아래 형식을 따름
{ (매개변수들) -> 반환 타입 in
실행코드
}
sorted(by:) 메서드에 클로저 전달
첫 번째 예시에서의 backwards(first:second:) 함수 대신에 sorted(by:) 메서드의 전달인자로 클로저를 직접 전달
let names: [String] = ["Sunny", "Kangkyung", "Yun"]
let reversed: [String] = names.sorted(by: { (first: String, second: String) -> Bool in
return first > second
})
print(reversed)
// print ["Yun", "Sunny", "Kangkyung"]
// 후행 클로저의 사용
let reversed: [String] = names.sorted() { (first: String, second: String) -> Bool in
return first > second
}
// sorted(by:) 메서드의 소괄호까지 생략 가능
let reversed: [String] = names.sorted { (first: String, second: String) -> Bool in
return first > second
}
클로저는 특정 문맥의 상수나 변수의 값을 캡쳐할 수 있습니다. 다시말해 원본 값이 사라져도 클로져의 body안에서 그 값을 활용할 수 있습니다.
A closure can capture constants and variables from the surrounding context in which it’s defined. The closure can then refer to and modify the values of those constants and variables from within its body, even if the original scope that defined the constants and variables no longer exists.
func makeIncrementer(forIncrement amount: Int) -> (() -> Int) {
var runningTotal = 0
func incrementer() -> Int {
runningTotal += amount
return runningTotal
}
return incrementer
}
// incrementByTwo 상수에 상수 할당
let incrementByTwo: (() -> Int) = makeIncrementer(forIncrement: 2)
// 각각의 incrementer의 동작
let incrementByTwo: (() -> Int) = makeIncrementer(forIncrement: 2)
let incrementByTwo2: (() -> Int) = makeIncrementer(forIncrement: 2)
let incrementByTen: (() -> Int) = makeIncrementer(forIncrement: 10)
let first: Int = incrementByTwo() // 2
let second: Int = incrementByTwo() // 4
let third = incrementByTwo() // 6
let ten: Int = incrementByTen() // 10
let twenty: Int = incrementByTen() // 20
let thirty: Int = incrementByTen() // 30
incrementByTwo와 incrementByTen은 모두 상수.
이 두 상수 클로저는 값 획득을 통해 runningTotal 변수를 계속해서 증가시킬 수 있음
→ Why? 함수와 클로저는 참조 타입이기 때문!
Whenever you assign a function or a closure to a constant or a variable, you are actually setting that constant or variable to be a reference to the function or closure. In the example above, it’s the choice of closure that incrementByTen refers to that’s constant, and not the contents of the closure itself.
This also means that if you assign a closure to two different constants or variables, both of those constants or variables refer to the same closure.
아래 예제에서 pink와 16진수와 AND 연산을 하게 되는데 여기서 FF는 윈도우 역할을 해서 AND연산에서 FF의 위치에 있는 값만 취해 시프트 연산을 하게 됩니다. ??? 🤔
let pink: UInt32 = 0xCC6699
let redComponent = (pink & 0xFF0000) >> 16 // redComponent is 0xCC, or 204
let greenComponent = (pink & 0x00FF00) >> 8 // greenComponent is 0x66, or 102
let blueComponent = pink & 0x0000FF // blueComponent is 0x99, or 153
클로저를 통해 비동기 콜백(call-back) ??? 🤔
자료 출처: