본문 바로가기
Ios

클로저에 대해서 알아보자

by 잘먹는 개발자 에단 2024. 8. 16.

클로저

- 익명함수 또는 내장함수라고 불립니다.

- 코드에서 일급 객체로 사용할 수 있는 기능블록입니다.

- 클로저는 코드에서 다른 함수로 전달되거나, 변수에 저장되거나, 나중에 호출될 수 있습니다.

- 함수와 매우 유사하지만 정확히 함수는 아닙니다.

 

 

클로저는 크게 3가지 형태로 사용됩니다. 

1. 전역함수 

_ 이름이 있으며, 특정 컨텍스트에 속하지 않습니다.

 

2. 중첩함수

_ 이름이 있으며, 다른 함수 내부에 정의됩니다.

 

3. 클로저 표현식

_ 이름이 없으며, 간결한 문법으로 작성할 수 있습니다. 일반적으로 이 형태를 클로저라고 부릅니다.

 

 

클로저의 기본문법

클로저는 입력 파라미터, 반환타입, 그리고 실행할 코드 블록으로 구성됩니다.

{ (parameters) -> returnType in
	// 실행할 코드
}

 

예시

let greeting = { (name : String) -> String in
	return "Hello, \(name)"
}

let message = greeting ("Alice")
print(message) // Hello, Alice

 

 

 

클로저는 다음과 같이 간단하게 작성할 수 있습니다.

1. 파라미터와 반환타입이 이미 정의되어있으면, 이를 생략할 수 있습니다.

let greeting = { name in 
	return "Hello \(name)"
}

 

2. 클로저가 단일 표현식으로 이루어져 있으면, return 키워드를 생략할 수 있습니다.

let greeting = { name in
	"Hello, \(name")
    // return 생략
}

 

3. 클로저에서 파라미터 이름을 $0, $1등으로 축약하여 사용할 수 있습니다.

let greeting = {"Hello, \($0)"}

 

4. 후행 클로저 _ 클로저가 함수의 마지막 인자로 전달될 때, 클로저를 함수 호출 괄호 밖에 작성할 수 있습니다.

// 원형
let sortedNames = names.sorted(by: { (first: String, second: String) -> Bool in
    return first < second
})


let names = ["james", "rodrigues", "john", "methew"]

// 1번째 형태 : 단일 표현식일 경우에 return을 생략할 수 있다.
let sortedNamesClosure1 = names.sorted( by : {
	(first: String, second : String) -> Bool in 
    	first < second
})


// 2번째 형태 : 반환형을 생략할 수 있다.
let sortedNamesClosure2 = names.sorted( by: {
	(first : String, second : String) in
    	first < second
})

// 3번째 형태 : 마지막 인자로 전달되는 클로저는 후행 클로저로 작성할 수 있다.
let sortedNamesClosure3 = names.sorted{
	(first : String, second : String) in
    	first < second
}

 

 

 

 

 

함수와 클로저의 차이점

    ㄴ 1. 함수는 이름을 가질 수 있지만, 클로저는 일반적으로 이름이 없는 익명함수입니다.

let greeting = { (name: String) -> String in
    return "Hello, \(name)!"
}

   

    ㄴ 2. 클로저는 정의된 범위 안의 변수나 상수를 캡쳐하여 저장할 수 있으나, 함수는 일반적으로 불가능합니다.

        아래 예시에서 클로저는 total과 incrementAmount를 캡쳐하여 함수가 호출된 후에도 사용할 수 있습니다.

func makeIncrementer(incrementAmount: Int) -> () -> Int {
    var total = 0
    let incrementer: () -> Int = {
        total += incrementAmount
        return total
    }
    return incrementer
}

let incrementByTwo = makeIncrementer(incrementAmount: 2)
print(incrementByTwo())  // 2
print(incrementByTwo())  // 4

   

    ㄴ 3. 클로저는 함수에 비해서 매우 간결한 문법을 사용할 수 있습니다. 특히 swift 에서는 클로저의 파라미터 및 반환 타입을 추론할 수 있으며, 파라미터 이름을 생략할 수 있습니다.

let doubled = numbers.map { $0 * 2 }

 

    ㄴ 4. 후행 클로저 _ 클로저는 함수의 마지막 인자로 전달될 때, 후행 클로저 문법을 사용할 수 있습니다. 함수는 이와 같은 특별한 문법이 없습니다.

let numbers = [1, 2, 3, 4, 5]
let doubled = numbers.map { $0 * 2 }

 

 

 

클로저의 주요 특징

1. 캡쳐 _ 클로저는 정의된 범위 내의 상수와 변수를 캡쳐하고 저장할 수 있습니다. 이로 인해서 클로저가 생성된 범위 밖에서도 해당 변수와 상수에 접근할 수 있습니다.

func makeIncrementer(incrementAmount: Int) -> () -> Int {
    var total = 0
    let incrementer: () -> Int = {
        total += incrementAmount
        return total
    }
    return incrementer
}

let incrementByTwo = makeIncrementer(incrementAmount: 2)
print(incrementByTwo())  // 2
print(incrementByTwo())  // 4

여기서 클로저는 total과 incrementAmount 변수를 캡쳐하여 클로저 내부에서 사용할 수 있습니다.

 

2. 탈출 클로저 escaping closures _ 함수가 반환된 후에도 실행될 수 있는 클로저를 말합니다. 이러한 클로저는 보통 비동기 작업에서 사용됩니다. 탈출 클로저는 함수의 파라미터로 전달될 때 @escaping 키워드가 필요합니다.

 

그러니까 performAsyncOperation 함수 실행이 끝난 후에 콜백으로 completion() 이 실행된다. 함수 동작 마지막에 수행되는게 아니라 끝난 다음에 콜백으로 호출되는 것이다. 

func performAsyncOperation(completion : @escaping () -> Void){
	DispatchQueue.global().async{
    	// 비동기 작업 수행
    	completion() // 작업이 끝난 후 클로저 호출
    }
}

 

3. 비탈출 클로저 _ 기본적으로 함수가 종료되기 전에 실행되어야 하는 클로저로 @escaping 키워드가 필요하지 않습니다.

'Ios' 카테고리의 다른 글

Ad Hoc으로 IOS 어플리케이션 내부 배포하기  (3) 2024.09.09
RESTful API 사용하기  (0) 2024.08.21
self에 대해서 알아보자  (0) 2024.08.16
struct 그리고 class  (0) 2024.08.16
as에 대해서 알아보자  (0) 2024.08.16