카테고리 없음

[Swift] 클로저(Closure)

dev_zoe 2023. 7. 13. 20:34
반응형

본 포스팅은 '스위프트 프로그래밍 (3판)' 도서 앨런 Swift 문법 마스터스쿨 강의를 참고하여

Swift 프로그래밍에 대해 정리하는 글입니다.

혹시 틀린 부분이 있거나 질문이 있으시다면 언제든지 댓글 달아주시면 정말 감사하겠습니다 :)


Closure, 클로저

1) 이름이 없는 함수이며, 함수와 기능이 완전히 동일함 (이름은 없으나 하나의 블록으로 묶여서 기능을 처리할 수 있는 문법)

{ (매개변수) -> 반환 타입 in 
	코드
}

 

 

 

2) 클로저는 일급 객체이다. (Swift에서는 함수가 일급 객체. 즉 클로저도 일급 객체)

 

*일급 객체란?

1) 변수에 할당 가능하다.

2) 파라미터로 전달 가능하다.

3) 반환 타입으로 사용할 수 있다.

 

3) 클로저는 참조 타입이다.

- 클래스와 같이 참조 타입으로, 마찬가지로 ARC에 의해 메모리가 관리되며 힙에 인스턴스가 생성됨

 

클로저의 문법 최적화

1) 후행 클로저(trailing closure)

- 메서드의 맨 마지막으로 전달되는 인자는 소괄호와 인자 생략 가능

func doSomething(callback: () -> ()) {
    print("시작")
    callback()
    print("끝")
}


doSomething(callback: {
    print("안녕하세요")
})
// 위와 아래가 완전히 동일한 표현
doSomething {
    print("안녕하세요")
}

- Xcode에서는 자동 완성을 통해 아래와 같이 파라미터 이름과 소괄호가 생략된 형태를 제공함

 

*Swift 5.3 ~ 멀티플 후행 클로저

- 꼭 마지막 인자가 아니더라도 다른 인자의 클로저도 후행 클로저 형태로 표현 가능해짐

func multipleClosure(first: () -> (), second: () -> (), third: () -> ()) {
    first()
    second()
    third()
}

multipleClosure(first: {
    print("1")
}, second: {
    print("2")
}) {
    print("3")
}

 

2) 문맥을 이용한 타입 유추

- 아래와 같이 매개변수 타입과 반환 타입 생략 가능

- 반환 타입이 명확할 경우에 return 키워드도 생략 가능

let closureType1: (Int) -> (Bool) = { num in
    return num%2 == 0
}

let closureType1: (Int) -> (Bool) = { num in
    num%2 == 0
}

 

3) 단축 인자 ($0, $1 ..)

- 첫번째 파라미터, 두번째 파라미터, 세번째 파라미터 ... 를 각각 $0, $1, $2... 로 나타낼 수 있다.

let closureType1: (Int) -> (Bool) = { num in
    num%2 == 0
}

closureType1(5)

// 위와 아래가 완전히 동일

let closureType2 = { $0 % 2 == 0 }
closureType2(5)

let closureType3: (Int, Int) -> Int = { (a, b) in
    return a * b
}

// 위와 아래 동일

let closure4: (Int, Int) -> Int = { $0 * $1 }

 

탈출 클로저(@escaping)

우리가 이전까지 배웠던 일반 클로저는 비탈출 클로저임 (함수의 실행이 종료되면, 파라미터로 쓰이는 클로저도 종료)

@escaping 키워드가 붙은 클로저는 함수가 종료되어도 클로저가 존재하도록 하는데, 이를 탈출 클로저라고 함

 

1) 외부 변수에 내부의 클로저를 저장할 경우

var func1: () -> () = { print("출력") }

func performEscaping2(closure: @escaping () -> ()) {
    func1 = closure         // 클로저를 실행하는 것이 아니라  aSavedFunction 변수에 저장
}

func1() // 출력


performEscaping2(closure: { print("다르게 출력") })

func1() // 다르게 출력

 

2) GCD, 비동기 프로그래밍에서 컴플리션 핸들러 역할로 사용 (함수의 작업을 종료하고 난 이후에 호출되어야 하는 기능을 이스케이핑 클로저로 정의)

func performEscaping1(closure: @escaping (String) -> ()) {
    
    var name = "홍길동"
    
    DispatchQueue.main.asyncAfter(deadline: .now() + 1) {   //1초뒤에 실행하도록 만들기
        closure(name)
    }
    
}



performEscaping1 { str in       // 1초 뒤에 클로저 실행
    print("이름 출력하기: \(str)")
}

 

 

=> 탈출 클로저는 본래 함수(클로저)와 달리, 더 오래 저장되어 있어야하므로 힙 영역에 저장되는 것으로 바뀜

(일반 비탈출 클로저는 함수와 똑같이 스택 영역에서 잠깐 생겼다가 끝나면 사라짐)

 

자동 클로저(@autoclosure)

함수의 전달 인자를 자동으로 중괄호를 붙여 클로저로 변환해주는 클로저를 자동 클로저라고 한다.

자동 클로저는 전달 인자를 갖지 않는 클로저에만 사용 가능하다.

다만 중괄호를 명시적으로 표시해주지 않으면 헷갈릴 가능성이 높으므로, 많은 사용은 지양하는 것이 좋다.

 

func someFuction(closure: @autoclosure () -> Bool) {
    if closure() {
        print("참입니다.")
    } else {
        print("거짓입니다.")
    }
}


var num = 1

someFuction(closure: num == 1)
반응형