post-custom-banner

참고

Swift는 함수형 프로그래밍 언어가 아님에도 불구하고, First-class-function을 가지고 있다. 그렇다면, Swift에서 First-class-function이 의미하는 바는 무엇일까?

What Are First-Class Functions?

Swift는 First-class-function을 가지고 있으며, 이것은 아래의 의미를 내포한다.

  1. function은 상수와 변수로 저장될 수 있다.
  2. function은 다른 function의 argument로 대입할 수 있다.
  3. function은 다른 function을 return 값으로 설정할 수 있다.

Swift에서 Function은 First-class citizens이며, 다양한 가능성을 가지고 있다는 것을 의미한다.

Storing Functions in Variables and Constants

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라 명한다(좀 명확하지는 않지만, 받아들이자..). sessionManagerdidSignOut 프로퍼티에 할당하는 Closure는 self에 대한 reference를 캡처합니다(그니까, 현재의 상황을 저장한다는 의미로 파악하면 될 듯?). 이것이 바로 클로저라는 용어를 사용하는 이유다.

Passing a Function As an Argument

때때로 UIView 클래스를 사용하여 애니메이션을 실행하는 것이 얼마나 간단한지 당연하게 여긴다. 아래의 예시는 좀 친숙하다. 우리는 likeButtonalpha 프로퍼티를 동작하기 위해 UIViewanimate(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로 호출하는 것은 가능한 일이다.

Returning a Function From a Function

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, 생명주기가 끝나지 않고 메모리에 계속 상주한다...!)

profile
RTFM
post-custom-banner

0개의 댓글