함수의 마지막 인수로 함수에 클로저 표현식을 전달해야하고 클로저 표현식이 긴 경우 후행 클로저를 사용한다고 합니다!
예제를 보면서 알아보았습니다.
func someFunctionThatTakesAClosure(closure: () -> Void) {
// function body goes here
}
// Here's how you call this function without using a trailing closure:
someFunctionThatTakesAClosure(closure: {
// closure's body goes here
})
// Here's how you call this function with a trailing closure instead:
someFunctionThatTakesAClosure() {
// trailing closure's body goes here
}
위의 코드에서 someFunctionThatTakesAClosure 함수는 하나의 매개변수를 가지고 있습니다.
이 매개변수는 closure라는 이름의 클로저입니다.
someFunctionThatTakesAClosure함수를 호출할 때 closure 매개변수에 클로저를 전달합니다. 클로저는 중괄호로 묶여 있습니다.
someFunctionThatTakesAClosure함수를 호출할 때 후행 클로저를 사용합니다!
후행클로저는 함수의 마지막 매개변수로 전달되기 때문에 매개변수 이름을 생략할 수 있습니다.
마지막 someFunctionThatTakesAClosure()의 부분을 보시면 코드를 더욱 간결하게 사용할 수 있습니다.
특히 함수의 마지막 매개변수가 클로저인 경우 후행클로저를 사용하면 코드가 더욱 깔끔해집니다!!
주의할 점은 후행 클로저는 함수의 마지막 매개변수로만 사용할 수 있다는 점입니다!
reversedNames = names.sorted() { $0 > $1 }
문자열 정렬 클로저는 메서드의 소괄호 밖에 작성될 수 있습니다!
reversedNames = names.sorted { $0 > $1 }
후행 클로저로 표현식이 함수와 메서드의 유일한 인수일 경우 함수를 호출할때 ()를 생략해도 좋습니다!
위의 예제는 0은 "Zero"등으로 숫자를 그에 해당하는 영어로 매핑하는 딕셔너리 입니다!
numbers 배열을 사용하여 후행 클로저로 map(_:)메서드로 클로저 표현식을 작성하여 String값의 배열을 생성 할 수 있습니다.
let strings = numbers.map { (number) -> String in
var number = number
var output = ""
repeat {
output = digitNames[number % 10]! + output
number /= 10
} while number > 0
return output
}
// strings is inferred to be of type [String]
// its value is ["OneSix", "FiveEight", "FiveOneZero"]
클로저 몸체를 보시면,
number를 number로 초기화 하고있습니다.
output 변수를 ""로 초기화 하고있습니다.
repeat으로 number가 0이 될때까지 반복합니다.
반복문의 각 반복에서 클로저는 number의 나머지를 구하고, 해당하는 영어 이름을 output변수에 추가합니다.
마지막으로 클로저는 output 변수의 값을 반환합니다.
따라서 map함수는 numbers 배열의 각 요소에 대해 위의 클로저를 실행하고, 각 요소에 대한 클로저의 결과를 배열 strings에 저장합니다.
( 딕셔너리의 서브 스크립트는 키가 존제하지 않는 경우에 값을 찾는걸을 실패하기 위해 옵셔널 값을 반환합니다! 따라서 digitNames뒤에 !를 붙여줍니다.)
함수가 여러개의 클로저를 가지고 있다면 첫번째 후행 클로저의 인수 라벨을 생략하고 남은 후행 클로저의 라벨을 표기합니다.
클로저를 실행하기 전에 num이란 값을 외부에서 변경하면 클로저 내부에서 사용하는 num의 값또한 변경됨!!
(다시 document로...)
Swift에서 값을 캡처할 수 있는 간단한 클로저 형태는 다른 분문 내에 작성하는 중첩함수 입니다.
중첩함수는 바깥 함수의 어떠한 인수도 캡처할 수 있고, 바깥 함수 내에 정의된 상수와 변수를 캡처 할 수 있습니다.
(이해가 조금 어려우니 예제를 보면서 이해하겠습니다!)
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0
func incrementer() -> Int {
runningTotal += amount
return runningTotal
}
return incrementer
}
incrementer는 중첩함수로 makeIncrementer함수의 내부에 정의되어 있습니다.
incrementer()함수는 둘러싸인 컨텍스트에 runningTotal과 amount값을 캡처합니다. 이값을 캡처한 후 incrementer는 호출할때마다
amount로 runningTotal을 증가시키는 클로저로 makeIncrementer에 의해 반환됩니다.
makeIncrementer의 반환타입은 () -> Int 입니다. 이것은 함수를 반환한다는 의미입니다!
incrementer() 함수는 파라미터가 없으며 함수 본문 내에 runningTotal 과 amount 를 참조하고 있습니다. 둘러싸인 함수에 runningTotal 과 amount 대한 참조 (reference) 를 캡처하고 함수 내에서 사용합니다. 참조를 캡처하는 것은 makeIncrementer 호출이 종료될 때 runningTotal 과 amount 가 사라지지 않고 다음에 incrementer 함수가 호출될 때 runningTotal 을 사용할 수 있습니다.
incrementer 함수는 파라미터가 없으며 함수 본문 내의 runningTotal과 amount를 참조하고 있습니다.
runningTotal과 amount에 대한 참조(reference)를 캡처하고 함수 내에서 사용합니다! 참조를 캡처하는 것은 makeIncrementer호출이 종료될 때 runningTotal과 amount가 사라지지 않고 다음에 incrementer함수가 호출될때 runningTotal을 사용할 수 있습니다!!
클로저는 참조 타입
참조하는 클로저는 캡처한 runningTotal을 계속 증가시킬수 있는 이유는 함수와 클로저가 참조타입(reference tpyes)이기 때문입니다!
뒷부분은 ARC를 공부한후 다시오도록! - 엡! 삐~
생각과 감정
이전엔 졸업까지 별로 남지 않아 마음이 많이 조급했던것 같습니다! 흠... 다른분들에게 조언을 받고 여러 유튜브 영상을 보아도 천천히 자기페이스에 맞춰서 공부하는게 모쪼록 도움이 크다고 했지요.. 하하 저도 천천히 저의 페이스에 따라 나아가려 합니다!!