연산자 함수

, < 이런거도 함수, 따라서 함수의 모양이 연산자 함수의 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

참조 타입의 캡처링의 경우 말그대로 참조이기 떄문에, 해당 참조 안의 값을 접근해 변경할 수 있다.

탈출 클로저