Swift/개념 & 응용

[Swift] Swift 문법 - 클로저(Closure)

유정주 2021. 8. 24. 00:10
반응형

안녕하세요.

 

오늘은 Swift의 클로저(Closure)에 대해 알아보도록 하겠습니다.

긴 함수를 독립적으로 선언하면서 짧고 간편하게 사용할 수 있습니다.

 

바로 시작하겠습니다.


참고 자료

해당 포스팅은 Smile Han님의 유튜브 영상을 참고하며 작성하였습니다.

https://www.youtube.com/channel/UCM8wseo6DkA-D7yGlCrcrwA

 

Smile Han

 

www.youtube.com


클로저(Closure)

클로저 표현식은 외부의 간섭을 받지 않는 독립적인 코드 블록입니다.

Java의 Lambda function과 비슷한 문법입니다.

클로저는 함수처럼 매개변수를 받거나, 값을 반환하도록 만들 수 있습니다.

 

클로저 선언 방법

함수와 선언하는 방법은 비슷한데 반환 타입 뒤에 in이 들어간다는 차이점이 있습니다.

{{<매개 변수 이름>: <매개변수 타입>, ...) -> <반환 타입> in
	//클로저 표현식 코드
}

클로저를 선언하고 상수에 할당한 다음, 함수를 호출할 수 있습니다.

 

함수 예시

func add(x: Int, y: Int) -> Int {
	return(x+y)
}
print(add(x: 10, y: 20))
//실행결과
//30

 

클로저 예시

let add = { (x: Int, y: Int) -> Int in
	return(x+y)
}
print(add(10, 20))
//실행결과
//30

함수와 달리 클로저는 따로 함수 선언 없이도 함수와 결과가 같습니다.


후행 클로저(trailing closure)

클로저가 함수의 마지막 매개변수에 들어간다면

마지막 매개변수 이름을 생략한 후 함수 소괄호 외부에 클로저를 구현할 수 있습니다.

코드가 짧아진다는 장점이 있지만

클로저에 대해 모르는 사람에게는 코드 해석에 어려움을 줄 수 있다.

 

Swift의 Alert를 예시로 들어보겠습니다.

Swift의 UIAlertAction 함수 마지막 매개변수의 이름은 handler입니다.

따라서 마지막 매개변수 이름을 생략하지 않는다면 아래처럼 작성합니다.

let onAction = UIAlertAction(title: "아니오", style: 
  UIAlertAction.Style.default,  handler: {
  	ACTION in self.lampImg.image = self.imgOn
  	self.isLampOn=true
})

trailing closure를 사용하면 아래처럼 handler 이름을 생략할 수 있습니다.

let onAction = UIAlertAction(title: "아니오", style: 
  UIAlertAction.Style.default) {
    ACTION in self.lampImg.image = self.imgOn
    self.isLampOn=true
}

default에서 바로 소괄호를 닫고 클로저를 선언하였습니다.

이렇게 후행 클로저(trailing closure)는 마지막 매개변수의 이름을 생략할 수 있습니다.


클로저의 축약 표현들

클로저는 다양한 방법으로 축약할 수 있습니다.

케이스마다 예시를 준비했으니 이해하기 쉬우셨으면 좋겠습니다.

 

아래 함수는 모든 예시에 사용되는 함수입니다.

예시들 위에 아래 함수를 작성하시면 됩니다.

//함수 기본 선언 예시 
func math(x: Int, y: Int, cal: (Int, Int) -> Int) -> Int {
	return cal(x, y)
}

 

기본 클로저 예시

let power = {(num: Int, pow: Int) -> Int in
    var result = 1
    for i in 0..<pow {
        result = result * num
    }

    return result
}

var result = power(2, 3)
print(result)
//실행결과
//8

기본적인 클로저 예시입니다.

위에서도 몇 번 언급했으나 기본은 중요하니 여러 번 강조하는 것도 좋은 것 같아요.

거듭제곱을 반환해주는 클로저입니다.

 

함수의 매개변수를 클로저로 사용

let result = math(x: 2, y: 3, cal: {(num: Int, pow: Int) -> Int in
	var result = 1
    for i in 0..<pow {
        result = result * num
    }

    return result
})

print(result)
//실행결과
//8

함수의 매개변수를 클로저로 사용한 예시입니다.

후행 클로저를 사용하지 않을 때는 마지막 매개변수를 생략하지 않으면 됩니다.

 

후행 클로저(trailing closure) 예시

let result = math(x: 2, y: 3) {(num: Int, pow: Int) -> Int in
    var result = 1
    for i in 0..<pow {
        result = result * num
    }

    return result
}

print(result)
//실행결과
//8

위의 예시를 후행 클로저를 사용하여 다시 작성해보았습니다.

y의 값을 설정한 뒤 바로 소괄호를 닫고 클로저를 작성해줍니다.

실제 앱 개발에서도 유용하게 사용할 듯합니다.

 

반환형 생략

let result = math(x: 2, y: 3) {(num: Int, pow: Int) in
    var result = 1
    for i in 0..<pow {
        result = result * num
    }

    return result
}

print(result)
//실행결과
//8

클로저는 반환형을 생략할 수 있습니다.

반환형은 추론이 가능하므로 클로저의 반환형은 생략이 가능합니다.

이 표현 형식도 코드를 줄이는데 큰 도움이 될 것 같습니다.

 

매개변수 생략, 단축 인자(shorthand argument name) 사용

let result = math(x: 2, y: 3) {
    return $0 + $1
}

print(result)
//실행결과
//5

클로저는 매개변수 전체를 생략 가능하고 매개변수 대신 단축 인자를 사용할 수 있습니다.

첫 번째 인수는 $0, 두 번째 인수는 $1로 $2, $3 쭉쭉 사용하시면 됩니다.

 

위의 거듭제곱 함수보다는 이처럼 아주 간단한 함수일 때 효과가 극대화된다고 생각하여 예시를 바꾸었습니다.

코드는 눈에 띄게 줄어들었고 가독성도 증가하였습니다.

다만 클로저를 모르는 사람에게는 단번에 이해하기 힘들 수도 있다는 생각이 드네요.

 

return 생략

let result = math(x: 2, y: 3) {
    $0 + $1
}

print(result)
//실행결과
//5

생략 가능한 모든 것을 생략한 형태입니다.

마지막 문장은 당연히 return일 것이므로 return 키워드조차 생략 가능합니다.

 

하지만 이렇게까지 생략하는 것은 클로저에 대해 알고 있다고 해도

순간적으로 헷갈릴 것 같네요.


오늘은 클로저에 대해 알아보았습니다.

클로저는 너무나도 다양한 형태가 있다는 것을 배웠습니다.

실제 코드에서는 사람에 따라, 상황에 따라 여러 형태가 혼합되어 보일 것이므로

이것이 클로저라는 것을 알고 있어야 코드를 해석하는데 어려움이 없을 것 같네요.

 

어떤 상황에서 어떤 표현이 가독성과 코드의 길이면에서 유리할지 고민해보아야겠습니다.

감사합니다!


아직은 초보 개발자입니다.

더 효율적인 코드 훈수 환영합니다!

공감 댓글 부탁드립니다.

 

 

반응형