, < 이런거도 함수, 따라서 함수의 모양이 연산자 함수의 Sig와 동일하다면 연산자 함수 사용할 수 있음.
// bigger than
public func ><T: Comparable>(lhs: T, rhs: T) -> Bool
let reversed = names.sorted(by: >)
기본적으로 클로저가 외부 값을 캡처링할 때는 value type이든 reference type이든
reference를 참조하게 된다.
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0
func incrementer() -> Int {
runningTotal += amount
return runningTotal
}
return incrementer
}
// 함수가 각기 실행되지만 실제로 변수 runningTotal, amout가 캡쳐링 되서 그 변수를 공유하기에 누적된 결과가 나온다.
let incrementByTen = makeIncrementer(forIncrement: 10)
print(incrementByTen()) // 10
print(incrementByTen()) // 20
// 새로운 클로저를 만들 경우에는 캡쳐링이 달라서 누적이 되지 않는다.
let incrementBySeven = makeIncrementer(forIncrement: 7)
print(incrementBySeven()) // 7
→ 위와 같은 경우의 이유가 클로저가 함수 내의 var runningTotal
이라는 reference를 캡처링 하기 때문이다.
reference를 참조하는 것이 아니라 값 자체를 참조해 값을 변경하지 않도록 하는 방법이 바로 획득 목록이다.
var x = 0
var y = 0
let block = { [x] in
print(x)
}
let unblock = {
print(x)
}
x += 1
block() // 0
unblock() // 1
이런 식으로 선언하게 되면 block 안의 x는 immutable의 형태로 초기화되기 때문에, 안에서 값을 바꿀 순 없지만 그 시점의 x값을 그대로 유지할 수 있다.
위는 값 타입이지만, 참조 타입을 획득 목록으로 사용하는 경우는 다르다.
참조 타입의 경우 획득을 어떻게 할지 정해줄 수 있다. strong, weak, unowned로 정해줄 수 있다.
약한 획득인 경우 Optional 상수로 지정된다. → 메모리에서 해제된 상태일 수 있기 때문.
class NewClass {
var value : Int = 0
}
var newClass : NewClass = NewClass()
print(newClass.value) // 0
let clousure: () -> Void = { [newClass] in
newClass.value += 1
}
clousure()
print(newClass.value) // 1
clousure()
print(newClass.value) // 2
참조 타입의 캡처링의 경우 말그대로 참조이기 떄문에, 해당 참조 안의 값을 접근해 변경할 수 있다.