반응형
여기 저기 널려있는 글들을 다시 요약하였다.
- 클로저
- 사용자의 코드 안에서 전달되거나 사용할 수 있는 기능을 포함한 독립적인 블록
- 자신이 정의된 컨텍스트 (context) 로부터 임의의 상수 및 변수의 참조(reference) 를 획득 (capture)하고 저장할 수 있습니다. (아래 값 획득하기 참조)
- 클로저의 경우 클로저 바로 밖의 scope 의 상수 및 변수에 접근할 수 있다는 이야기입니다)
- 이렇게 상수 및 변수를 제약하는 특징때문에 클로저라는 이름이 되었습니다.
- Swift는 획득 과정의 메모리 관리를 모두 제어해줍니다
- 클로저는 함수와 그 주변 환경에서 함수를 계산하는데 꼭 필요한 정보를 묶어서 저장해 둔 덩어리
- javascript 의 클로저, C# 의 람다
- 클로징
- 문맥에서 참조를 잡아서 저장하는 과정을 클로징 이라고 한다. 상수와 변수에 대해 그렇게 닫기 때문에 클로저라고 부른다.
- 클로저의 3가지 형태
- 전역 함수 : 이름은 있지만 아무 값도 획득하지 않는 클로저 ? - 그냥 함수다.
- 중첩함수 : 이름이 있고, 내부의 함수의 값을 획득하는 클로저 ? - 주변의 상수를 획득할 수 있는 구조
- 클로저 표현식 : 자신을 둘러싼 컨텍스트에서 값을 획득할 수 있는 가벼운 문법 ? - 람다 코드 블럭
- 전역 함수는 왜 클로징 하지 않나?
- 결국 변수가 모든 곳에서 참조가 가능하기 때문
더 공부하기
MV - V - VM (MVVVM) + Command 패턴 C# WPF 에서 널리 쓰여지는… 디자인 패턴
클로저 표현식 (Closure expressions) inline closures
중첩함수는 더 큰 함수의 일부로서 동작 -> 함수내의 반복되는 코드들을 함수화
완전한 선언이나 이름이 없는 함수 구조 -> 다른 함수들을 하나 또는 그 이상의 인자로 받는 함수를 만들 때
EX) 정렬함수의 진화 (sorted)
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
함수 표현식
func backwards(s1: String, s2: String) -> Bool {
return s1 > s2
}
var reversed = sorted(names, backwards)
// reversed i s equal to ["Ewa", "Daniell a", "Chris", "Barry", "Alex"]
클로저 표현식
- 중괄호 안에 쓰여져야 한다.
{ ( parameters ) -> return type in
statements
}
reversed = sorted(names, { (s1: String, s2: String) -> Bool in return s1 > s2 } )
컨텍스트로부터 타입 유추하기
(String, String) -> Bool 인라인 클로저 표현 형태로 클로저를 함수에 전달할 경우 인자와 반환 값의 타입을 유추할 수 있다. (생략)
reversed = sort(names, { s1, s2 in return s1 > s2 } )
단일 표현식 클로저로부터의 암시적 반환
s1>s2 의 결과값음 Bool 형태이기 때문에 Bool 과 return 을 생략할 수 있다.
reversed = sort(names, { s1, s2 in s1 > s2 } )
단축 인자 이름들
Swift는 자동으로 단축 인자 이름을 인라인 클로저에 제공하며, 클로저의 인자들은 $0, $1, $2 등등의 방식으로 참조할 수 있다.
이러한 단축 인자 이름들을 클로저 표현식에서 사용할 경우, 인자 리스트를 클로저의 정의에서 생략할 수 있다. 또한 in 키워드도 생략 할 수 있다
reversed = sort(names, { $0 > $1 } )
연산자 함수들
String에 특화된 크기 비교 연산자 > 를 두 String 인자의 비교로 유추함
reversed = sort(names, > )
후행 클로저 (Trailing Closures)
후행 클로저는 함수 표현식으로 함수 괄호 밖에서 작성되어 지원함
긴 클로저 표현식을 함수의 마지막 인자로 함수를 전달할 필요가 있다면 후행 클러저로 유용하게 대신 사용할 수 있다.
func someFunctionThatTakesAClosure(closure: () -> ()) {
// function body goes here
}
// here's how you call this function without using a trailing closure:
someFunctionThatTakesAClosure({
// closure's body goes here
})
// here's how you call this function with a trailing closure instead:
someFunctionThatTakesAClosure() {
// trailing closure's body goes here
}
후행 클로저는 클로저가 충분히 길어서 줄 안이나 한 줄 정도로 기술할 수 없는 경우에 아주 유용합니다. -> 클로저 부분을 맨 뒤로 뺌으로 써 가독성을 높인다.
let digitNames = [
0: "Zero", 1: "One", 2: "Two", 3: "Three", 4: "Four",
5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"
]
let numbers = [16, 58, 510]
let strings = numbers.map {
(var number) -> String in
var output = ""
while number > 0 {
output = digitNames[number % 10]! + output
number /= 10
}
return output
}
// strings is inferred to be of type String[]
// its value is ["OneSix", "FiveEight", "FiveOneZero"]
16 = “One” + “Six"
58 = “Five” + “Eight"
510 = “Five” + “One” +”Zero"
값 획득하기 (Capturing Values)
- 클로저는 자신이 정의된 주변 컨텍스트로부터 상수 및 변수의 값을 획득할 수 있습니다.
- 클로저는 이러한 상수와 변수들을 원래 상수와 변수들이 정의된 범위 (scope) 가 더이상 존재하지 않는 경우에조차도 값을 참조하거나 수정할 수 있습니다.
- Swift에서 클로저의 가장 간단한 형태는 다른 함수의 본문 안에 작성된 중첩 함수입니다.
- 중첩 함수는 바깥 함수의 모든 인자를 획득할 수 있으며, 또한 바깥 함수 내에서 정의된 모든 상수 및 변수를 획득할 수 있습니다.
아래는
Incrementor
라는 중첩 함수를 포함한 makeIncrementor
예입니다.중첩된
incrementor
함수는 runningTotal
및 amount
의 두 값을 자신을 둘러싼 컨텍스트로부터 획득합니다.이 두 값을 획득한 후,
incrementor
는 호출될 때 마다 runningTotal
을 mount
만큼 증가시키는 클로저로써makeIncrementor
로부터 반환됩니다.
func makeIncrementor(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0
func incrementor() -> Int {
runningTotal += amount
return runningTotal
}
return incrementor
}
let incrementByTen = makeIncrementor(forIncrement: 10)
let incrementBySeven = makeIncrementor(forIncrement: 7)
incrementByTen() // 10 반환
incrementBySeven() // 7 반환
incrementByTen() // 20 반환
incrementByTen() // 30 반환
참조 타입인 클로저 (Closure Are Reference Types)
위에 예제에서 incrementBySeven과 incrementByTen은 상수지만 클로저는 여전히 runningTotal 변수를 증가시키도록 참조함.
이것은 함수와 클로저는 참조 타입이기 때문임.
함수나 클로저를 상수에 할당하는 때는 그 상수에 함수나 클로저를 가르키는 참조를 할당하는 것임.
위의 예제에서 incrementByTen 상수는 클로저를 참조하며, (클로저 내용은 아님.)
이 의미는 다른 두개의 상수나 변수에 동일한 클로저를 할당하면 같은 클로저를 참조한다는 의미.