English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Swift 클로저

이 문서에서는 예제를 통해 클로저가 무엇인지, 문법, Swift의 클로저 유형을 배울 것입니다.

Swift 함수 문에서는 func 키워드를 사용하여 함수를 생성했습니다. 그러나 Swift에는 func 키워드와 함수 이름을 사용하지 않고 클로저를 정의할 수 있는 또 다른 특별한 함수 유형이 있습니다.
함수와 마찬가지로 클로저는 매개변수를 받아 값을 반환할 수 있습니다. 또한, 호출 후 실행되는 일련의 문장을 포함하고 있으며, 이를 함수로 변수에 할당할 수 있습니다/고정값.

Swift의 클로저는 C와 Objective-C의 코드 블록(blocks)과 다른 프로그래밍 언어의 익명 함수는 비교적 유사합니다.

전역 함수와 내장 함수는 특별한 클로저입니다.

클로저의 형태는 다음과 같습니다:

전역 함수내장 함수클로저 표현식
이름이 있는 클로저지만 어떤 값도 캡처할 수 없습니다.이름이 있는 클로저는 감싸인 함수 내의 값을 캡처할 수 있습니다.알려지지 않은 클로저는 가벼운 문법을 사용하여 컨텍스트에 따라 값을 캡처할 수 있습니다.

Swift의 클로저는 많은 최적화가 있습니다:

  • 컨텍스트에 따라 매개변수와 반환 타입을 추론합니다

  • 단一行 표현식 클로저에서는 자동으로 반환됩니다(즉, 클로저 본문이 단一行인 경우 return을 생략할 수 있습니다).

  • 간단한 매개변수 이름을 사용할 수 있습니다. 예를 들어 $0, $1(0부터 시작하여 i번째 매개변수를 나타냅니다...)

  • 트레일링 클로저 문법(Trailing closure syntax)을 제공합니다

문법

다음은 매개변수를 받아 지정된 타입을 반환하는 클로저 문법을 정의한 것입니다:

{(parameters) -> return type in
   statements
}

온라인 예제

let simpleClosure = {
    print("Hello, World!")
}
simpleClosure()

위 프로그램 실행 출력 결과는 다음과 같습니다:

Hello, World!

다음과 같은 형태의 클로저가 두 가지 매개변수를 받아布尔 값을 반환합니다:

{(Int, Int) -> Bool in
   Statement1
   Statement 2
    ---
   Statement n
}

온라인 예제

let simpleClosure:(String) -> (String) = { name in
    
    let greeting = "Hello, World!" + "Program"
    return greeting
}
let result = simpleClosure("Hello, World")
print(result)

위 프로그램 실행 출력 결과는 다음과 같습니다:

Hello, World! Program

클로저 표현식

클로저 표현식은 내장된 문법을 사용하여 인라인 클로저를 구축하는 방법입니다. 클로저 표현식은 클로저를 쓰는 데 일부 문법 최적화를 제공하여 클로저를 간결하고 명확하게 작성할 수 있게 합니다.

sorted 메서드를 제공합니다

Swift 표준 라이브러리는 sorted(by:) 의 메서드는 제공한 정렬 클로저 함수에 따라 알려진 타입 배열의 값을 정렬합니다.

정렬이 끝나면, sorted(by:) 메서드는 원래 배열과 같은 크기의 새 배열을 반환합니다. 이 새 배열은 같은 타입의 요소를 포함하고, 요소가 올바르게 정렬되어 있습니다. 원래 배열은 sorted(by:) 메서드로 인해 변경되지 않습니다.

sorted(by:) 메서드는 두 가지 매개변수를 전달해야 합니다:

  • 알려진 타입의 배열

  • 클로저 함수는 배열 요소 타입과 같은 두 가지 값을 전달받아布尔형 값을 반환하여 정렬이 끝나면 첫 번째 매개변수가 두 번째 매개변수 앞에 있든 뒤에 있든을 나타냅니다. 첫 번째 매개변수 값이 두 번째 매개변수 값보다 앞에 있으면, 정렬 클로저 함수는 다음과 같이 반환해야 합니다. true반대로 false

온라인 예제

import Cocoa
let names = ["AT", "AE", "D", "S", "BE"]
// 정상적인 함수(또는 내장 함수)를 사용하여 정렬 기능을 제공하면, 클로저 함수 유형은 (String, String)이어야 합니다 -> Bool。
func backwards(s1: String, s2: String) -> Bool {
    return s1 > s2
}
var reversed = names.sorted(by: backwards)
print(reversed)

위 프로그램 실행 출력 결과는 다음과 같습니다:

["S", "D", "BE", "AT", "AE"]

)보다 큽니다1)가 두 번째 문자열 (s2) backwards 함수가 true를 반환하면 새로운 배열에서 s1에 나타나야 합니다2문자열의 문자에 대해, " 큰 그림자 "는 " 알파벳 순서에서 나중에 나타나는 "을 의미합니다. 이는 문자 "B"가 문자 "A"보다 크고, 문자열 "S"가 문자열 "D"보다 크다는 것을 의미하며, 문자열이 역순으로 정렬됩니다. "AT"는 "AE"보다 앞에 있습니다.

파라미터 이름 축약을 통해 직접 호출할 수 있습니다.

Swift는 인라인 함수에 대해 파라미터 이름 축약 기능을 제공하며, $0, $1,2클로저의 파라미터를 순서대로 호출합니다.

온라인 예제

import Cocoa
let names = ["AT", "AE", "D", "S", "BE"]
var reversed = names.sorted(by: { $0 > $1 })
print(reversed)

$0와 $1String 타입의 첫 번째와 두 번째 파라미터를 나타냅니다.

위 프로그램 실행 출력 결과는 다음과 같습니다:

["S", "D", "BE", "AT", "AE"]

클로저 표현식에서 파라미터 이름 축약을 사용하면, 함수 유형을 통해 파라미터 이름 축약의 타입을 추론할 수 있으며, in 키워드도 생략할 수 있습니다.

연산자 함수

실제로 위의 예제에서의 클로저 표현식을 더 짧게 쓸 수도 있습니다.

Swift의String타입이 큰 그림자 (>)의 문자열 구현을 사용하여, 이는 두 개의 함수를 받는 함수로서 사용됩니다String타입의 파라미터를 받아서 반환합니다Bool타입의 값. 이것이 정확히 일치합니다sort(_)메서드의 두 번째 파라미터가 필요한 함수 유형과 일치해야 합니다. 따라서, 간단히 큰 그림자를 전달하면 됩니다. Swift는 자동으로 문자열 함수를 사용하려는 것을 추론할 수 있습니다:

import Cocoa
let names = ["AT", "AE", "D", "S", "BE"]
var reversed = names.sorted(by: >)
print(reversed)

위 프로그램 실행 출력 결과는 다음과 같습니다:

["S", "D", "BE", "AT", "AE"]

테일 클로저

트레일링 클로저는 함수 괄호 뒤에 쓰인 클로저 표현식으로, 함수는 이를 마지막 파라미터로 호출할 수 있습니다.

func someFunctionThatTakesAClosure(closure: () -> Void) {
    // 함수 본문 부분
}
// 함수 호출에 대한 트레일링 클로저를 사용하지 않습니다
someFunctionThatTakesAClosure({
    // 클로저 본문
)
// 함수 호출에 대한 트레일링 클로저를 사용합니다
someFunctionThatTakesAClosure() {}}
  // 클로저 본문
}

온라인 예제

import Cocoa
let names = ["AT", "AE", "D", "S", "BE"]
//테일 클로저
var reversed = names.sorted() { $0 > $1 }
print(reversed)

sort() 이후 { $0 > $1}을 테일 클로저로 사용합니다

위 프로그램 실행 출력 결과는 다음과 같습니다:

["S", "D", "BE", "AT", "AE"]

주의: 함수가 클로저 표현식의 하나의 매개변수만 필요하다면, 테일 클로저를 사용할 수 있습니다()생략

reversed = names.sorted { $0 > $1 }

포획 값

클로저는 그가 정의된 상황에서 상수나 변수를 포획할 수 있습니다

이 상수나 변수를 정의한 원래 영역이 존재하지 않더라도, 클로저는 여전히 클로저 함수 내에서 이 값을 참조하고 수정할 수 있습니다

Swift에서 가장 간단한 클로저 형식은 내부 함수입니다. 이는 다른 함수 내에서 정의된 함수를 의미합니다

내부 함수는 외부 함수의 모든 매개변수와 정의된 상수 및 변수를 포획할 수 있습니다

이 예제를 보세요:

func makeIncrementor(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    func incrementor() -> Int {
        runningTotal += amount
        return runningTotal
    }
    return incrementor
}

Int형의 매개변수 amout을 가진 함수 makeIncrementor가 있으며, 외부 매개변수 이름 forIncremet을 가지고 있어, 호출할 때는 반드시 이 이름을 사용해야 합니다. 반환 값은()-> Int의 함수

함수 내에서는 변수 runningTotal과 함수 incrementor를 선언했습니다

incrementor 함수는 아무도 매개변수를 가져오지 않지만, 함수 내에서 runningTotal과 amount 변수에 접근합니다. 이는 그가 포획한 함수 내에서 이미 존재하는 runningTotal과 amount 변수를 통해 이루어진 것입니다

amount 변수를 변경하지 않았기 때문에, incrementor는 실제로는 이 변수의 복사본을 포획하고 저장하며, 이 복사본은 incrementor와 함께 저장됩니다

따라서 이 함수를 호출할 때마다 누적됩니다:

import Cocoa
func makeIncrementor(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    func incrementor() -> Int {
        runningTotal += amount
        return runningTotal
    }
    return incrementor
}
let incrementByTen = makeIncrementor(forIncrement: 10)
// 반환된 값은10
print(incrementByTen())
// 반환된 값은20
print(incrementByTen())
// 반환된 값은30
print(incrementByTen())

위 프로그램 실행 출력 결과는 다음과 같습니다:

10
20
30

클로저는 참조형 데이터 타입입니다

위의 예제에서 incrementByTen는 상수입니다만, 이 상수가 가리키는 클로저는 여전히 그가 포획한 변수 값을 증가시킬 수 있습니다

이는 함수와 클로저가 모두 참조형 데이터 타입이기 때문입니다

함수를 무엇으로든 할당하든/클로저를 상수나 변수에 할당하든 상관없이, 실제로는 상수를 할당하고 있습니다/변수의 값이 해당 함수로 설정됩니다/클로저의 참조입니다. 위의 예제에서 incrementByTen는 클로저의 참조를 가리키는 상수이며, 클로저의 내용 자체가 아닙니다.

이것은 또한 여러분이 클로저를 두 개의 다른 상수에 할당했을 때 이를 의미합니다:/변수, 두 값이 모두 같은 클로저를 가리키게 됩니다:

import Cocoa
func makeIncrementor(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    func incrementor() -> Int {
        runningTotal += amount
        return runningTotal
    }
    return incrementor
}
let incrementByTen = makeIncrementor(forIncrement: 10)
// 반환된 값은10
incrementByTen()
// 반환된 값은20
incrementByTen()
// 반환된 값은30
incrementByTen()
// 반환된 값은40
incrementByTen()
let alsoIncrementByTen = incrementByTen
// 반환된 값도50
print(alsoIncrementByTen())

위 프로그램 실행 출력 결과는 다음과 같습니다:

50