[Swift] 19. 클로저

Hoojeong Kim·2022년 3월 11일
0

Swift Base

목록 보기
21/22
post-thumbnail

클로저(Closure)

클로저는 코드에서 전달 및 사용할 수 있는 독립 기능 블록이며, 1급 객체의 역할을 할 수 있다. 이때 1급 객체란 전달 인자로 보낼 수 있고, 변수/상수 등으로 저장하거나 전달할 수 있으며 함수의 반환 값이 될 수도 있는 객체를 의미한다.

보통 클로저는 이름 없는 함수, 익명 함수를 지칭한다. 하지만, 사실 클로저는 두 개의 형태로 나뉜다.

  • named closure
  • unnamed closure

여기서 named 클로저는 바로 우리가 말하는 함수이다. 그래서 보통 클로저를 지칭할 때는 익명 함수를 뜻한다.

클로저 표현식

클로저는 다음과 같은 방법으로 나타낸다.

{ (매개 변수) -> 리턴 타입 in
  실행 구문
}

익명 함수이기 때문에 func 키워드를 사용하지 않는다. 또한, 클로저는 in 키워드를 중심으로 앞은 closure head, 뒤는 closure body 라고 한다.

클로저 사용하기

위 표현식을 따라 클로저를 직접 사용해보자.

파라미터와 리턴 타입이 없는 클로저

let hello = { () -> () in
	print("hello")
}

hello()
hello

클로저를 호출할 때는, 일반 함수를 호출할 때와 마찬가지이다.

파라미터와 리턴 타입이 있는 클로저

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

hello2("Hoojeong")
hello, hoojeong

📌 주의할 점

함수에서 배운 것과 마찬가지로 파라미터 네임이 단독으로 쓰였으니 파라미터 이름이자, 전달인자 레이블이라고 생각할 수 있다. 하지만 클로저는 전달인자 레이블을 사용하지 않는다. 따라서 그냥 파라미터 이름이다.

함수의 파라미터로 전달하는 클로저

func doSomething(closureParameter: () -> ()) {
	closureParameter()
}

doSomething(closureParameter: { () -> () in
	print("hello")
})
hello

코드를 보면, 먼저 doSomething 함수는 클로저를 파라미터로 받고, 이를 실행한다. 그 다음, doSomething 함수를 호출할 때 파라미터로 클로저를 작성한다.(중괄호부터 중괄호까지가 클로저!)

이때 closureParameter는 doSomething 함수의 전달인자 레이블이자 파라미터 이다.

함수의 반환타입으로 사용하는 클로저

func doSomething2() -> () -> () {
	return { () -> () in
    	print("hello")
    }
}

doSomething2()()
hello

후행 클로저

클로저가 조금 길어지거나 가독성이 떨어진다 싶으면 후행 클로저를 사용하면 좋다. 단, 후행 클로저는 맨 마지막 전달인자로 전달되는 클로저에만 해당되므로 전달인자로 클로저 여러 개를 전달할 때는 맨 마지막 클로저만 후행 클로저로 사용할 수 있다.

함수의 파라미터가 하나인 후행 클로저

아까는 아래처럼 doSomething 함수를 호출할 때, 클로저의 파라미터와 반환 타입을 모두 작성했다.

func doSomething(closureParameter: () -> ()) {
	closureParameter()
}

doSomething(closureParameter: { () -> () in
	print("hello")
})

이를 후행 클로저를 사용해 바꾸면 아래와 같다.

func doSomething(closureParameter: () -> ()) {
	closureParameter()
}

doSomething() {
	print("hello")
}

파라미터와 반환 타입이 없는 클로저를 전달 받기 때문에 클로저를 정의할 때 파라미터와 반환 타입을 생략할 수 있고, in 키워드도 생략할 수 있다.


이때, doSomething 함수처럼 하나의 클로저만을 파라미터로 받는 경우에는 아래처럼 소괄호도 생략할 수 있다.
doSomething {
	print("hello")
}

함수의 파라미터가 여러 개인 다중 후행 클로저

다음 함수는 success와 fail이라는 두 개의 파라미터가 선언되어 있다. 이 함수에 다중 후행 클로저를 적용해보자.

func doSomething3(success: () -> (), fail: () -> ()) {

}

doSomething3 {

} fail: {

}

위처럼 파라미터를 중괄호로 각각 구분하고, 첫 번째 파라미터의 이름은 생략한다.

클로저 표현의 간소화

문법을 최적화해 클로저를 단순하게 표현할 수 있다.

아래 doSomething4 함수는 클로저를 파라미터로 하고, 클로저의 파라미터로는 Int 3개를, 클로저의 반환 타입은 Int를 전달한다.

func doSomething4(closure: (Int, Int, Int) -> Int) {
	closure(1,2,3)
}

위 함수를 경량 문법을 사용하지 않고 호출하면 아래와 같다.
doSomething4(closure: { (a: Int, b: Int, c: Int) -> Int in
	return a+b+c
})

그렇다면, 이제 경량 문법을 적용한 코드들을 살펴보자.

파라미터 형식과 리턴 형식 생략

doSomething4(closure: { (a, b, c) in
	return a+b+c
})

약식 인수 이름(Shortand Argument Names)을 통한 생략

각 파라미터를 $index로 대체한다.

따라서 a -> $0, b -> $1, c -> $2가 된다.

doSomething4(closure: {
	return $0 + $1 + $2
})

단일 return 생략

클로저 코드 블럭 내에 return 구문만 있을 경우, return 키워드를 생략할 수 있다.

doSomething4(closure: {
	$0 + $1 + $2
})

만약 아래와 같이 코드가 여러 줄일 때 return 키워드를 생략하면 에러가 발생한다.
doSomething4(closure: {
	print("hello")
    $0 + $1 + $2
})

후행 클로저를 사용한 생략

doSomething4() {
	print("hello")
    $0 + $1 + $2
}

파라미터 클로저가 하나일 때의 생략

doSomething4 {
	print("hello")
    $0 + $1 + $2
}
profile
나 애기 개발자 👶🏻

0개의 댓글