Swift는 함수형 프로그래밍 언어가 아님에도 불구하고, First-class-function
을 가지고 있다. 그렇다면, Swift에서 First-class-function
이 의미하는 바는 무엇일까?
Swift는 First-class-function
을 가지고 있으며, 이것은 아래의 의미를 내포한다.
- function은 상수와 변수로 저장될 수 있다.
- function은 다른 function의 argument로 대입할 수 있다.
- function은 다른 function을 return 값으로 설정할 수 있다.
Swift에서 Function은 First-class citizens
이며, 다양한 가능성을 가지고 있다는 것을 의미한다.
Swift에서 function은 first-class citizens이므로, 상수 또는 변수로 저장되는 것이 가능하다. 아래의 예시를 보자. SessionManager
는 프로퍼티로서 didSignOut
을 정의했다. 해당 프로퍼티는 Optional 타입임과 동시에 아무 argument를 가지지 않고 Void
를 return한다.
그리고, destroySession()
메소드는 didSignOut
프로퍼티의 참조를 가지는 function을 호출하며, didSingOut
프로퍼티의 값에 안전하게 접근하기 위해 Optional chaining을 사용하고 있다.
internal final class SessionManager {
// MARK: - Properties
var didSignOut: (() -> Void)?
// MARK: - Helper Methods
private func destroySession() {
didSignOut?()
}
}
아래의 예시에서, closure 구문을 통해 SessionManager
인스턴스의 didSignOut
프로퍼티에 값을 설정했다.
// Configure Session Manager
sessionManager.didSignOut = { [weak self] in
self?.showSignInView()
}
!! closure를 간단히 말하면, function이다. 만약 function이 상수와 변수를 기정의된 주변 환경의 항목(surrounding context)을 저장(capture)한다면, 이때 function을 closure라 명한다(좀 명확하지는 않지만, 받아들이자..). sessionManager
의 didSignOut
프로퍼티에 할당하는 Closure는 self
에 대한 reference를 캡처합니다(그니까, 현재의 상황을 저장한다는 의미로 파악하면 될 듯?). 이것이 바로 클로저라는 용어를 사용하는 이유다.
때때로 UIView
클래스를 사용하여 애니메이션을 실행하는 것이 얼마나 간단한지 당연하게 여긴다. 아래의 예시는 좀 친숙하다. 우리는 likeButton
의 alpha
프로퍼티를 동작하기 위해 UIView
의 animate(withDuration:animation:)
을 호출한다.
// Hide Like Button
UIView.animate(withDuration: 1.0) {
self.likeButton.alpha = 0.0
}
첫 argument는 animation의 duration이고, 두번째 argument는 closure다. Swift에서 Function은 first-class citizens이므로 animate(withDuration:animations:)
메소드의 두번째 arg로 Closure로 호출하는 것은 가능한 일이다.
Function에서 Function를 반환하는 것이 이상하게 들릴 수 있지만, 구문을 고려하면 그럴 수도 있다고 한다.. 아래의 예시를 확인해보자.
func increment(by increment: Int) -> (Int) -> Int {
{ (value) in value + increment }
}
우리는 Int
타입을 가지는 increment(by:)
function을 정의했다. increment(by:)
function의 return 타입은 function 타입이다. Return되는 함수는, Int
를 arg로 받으며, Int
를 Return한다 ㅎㅎ(그니까, 앞뒤를 쪼개서 보면 된다, (by increment: Int) 앞, (Int) -> Int 뒤)
.
func increment(by increment: Int) -> ((Int) -> Int) {
{ (value) -> Int in
value + increment
}
}
let incrementByFive = increment(by: 5)
그렇다면, increment(by increment)
function을 사용해보자. 우리는 해당 Function을 호출했고, 5
(Int)값을 넘겼다. 그리고, increment(by:5)는 incrementByFive
라는 상수에 해당 return 값이 저장되었다.
앞서 살펴본 것처럼 first-class function
은 변수와 상수로 저장할 수 있다. incrementByFive
상수는 increment(by: 5)
의 reference를 가진다. 즉, incrementByFive에 저장된 function을 호출할 수 있다(여기가 바로 Closure의 capture, 생명주기가 끝나지 않고 메모리에 계속 상주한다...!)