본문 바로가기

Swift 5.2 업데이트 내역 살펴보기

기술적인 이야기/애플 플랫폼 개발 2020. 3. 25.
반응형

이 글은 스위프트 공식 블로그의 Swift 5.2 Released! 글에서 언급한 두 가지 업데이트된 기능을 살펴보는 글입니다. 이 외에도 사실 여러 업데이트가 있겠지만 아무래도 이게 핵심이니까 언급한 것이겠죠?

키 경로 표현식을 함수처럼 사용하기

SE-0249 Key Path Expressions as Functions 제안을 통해 Swift 5.2에 구현된 기능입니다.

이 기능은 함수나 클로져를 넘겨서 처리하는 다양한 기능에서 함수나 클로져 대신 키 경로(Key Path)를 넘기는 것으로 구현을 간단하게 할 수 있도록 해줍니다. 간단하게 위의 제안 내용의 예제를 인용해 보겠습니다.

우선 아래의 구조체 User를 선언했습니다.

struct User {
    let email: String
    let isAdmin: Bool
}

이걸 이용해 데이터를 생성해 볼게요.

let users: [User] = [
    User(email: "sam@foo.com", isAdmin: false),
    User(email: "jack@foo.com", isAdmin: true),
    User(email: "james@bar.com", isAdmin: false)
]

만약 여기서 email의 내용만 따로 추출해 내려고 할 때 우리는 지금까지 아래와 같은 코드를 사용할 수 있었습니다.

users.map { $0.email }   // 1번 예제
// => ["sam@foo.com", "jack@foo.com", "james@bar.com"]

그런데 Swift 5.2부터는 아래와 같은 식으로 좀 더 단순화시킬 수 있습니다.

users.map(\.email)      // 2번 예제
// => ["sam@foo.com", "jack@foo.com", "james@bar.com"]

1번 예제에서는 map을 호출할 때 표현식으로 (User) -> String 타입의 클로저가 사용되었습니다. 그런데 이 (User) -> String 클로져 구현을 2번 예제에서는 간단히 \.email 만으로 끝내버릴 수 있게 된 것이네요.

위 예제를 좀 다르게 표현하면 아래와 같습니다.

let f: (User) -> String = \.email
users.map(f)
// => ["sam@foo.com", "jack@foo.com", "james@bar.com"]

f(User) -> String 타입의 클로저 타입인데 여기다 그냥 \.email이라는 키 경로를 대입했는데 이게 된다는 겁니다 글쎄. 와 신기해라.

위 제안 내용에는 이보다 더 다양한 표현 방법을 소개하고 있습니다만 일부는 되지 않는 경우도 있어서 일단 제외했습니다. 아무래도 Xcode 11.4가 Swift 5.2의 첫 버전이니 오류가 있을 가능성도 있지요. (아니면 제 이해가 부족하거나😭)

솔직히 소감은 잘... 모르겠네요. 가독성이 많이 좋아지는 것도 아니고 코드도 살짝 짧아진 정도입니다. 하지만 이런 기능을 굳이 구현한 이유는 아마도 다른 기능 구현에서 좀 더 편리함을 주려는 요소가 아닐지 생각됩니다. Property Wrapper도 SwiftUI를 위한 큰 그림이었던 것처럼 말이죠.

 

자신을 호출시킬 수 있는 타입

제목을 짓는데 상당히 난감한 SE-0253 Callable values of user-defined nominal types 제안을 통해 Swift 5.2에 구현된 기능입니다.

일단 값이라고 적긴 했는데 struct든 class든 다 되는 기능입니다. 핵심은 callAsFunction이라는 특수한 메서드를 구현할 수 있게 되었다는 점입니다. 이 메서드는 해당 인스턴스가 직접 호출될 때 호출되는 메서드입니다.

이해가 안 될 것 같으니 다짜고짜 예제로 넘어갑니다. 아래의 구조체를 하나 만들었습니다.

struct Grower {
    var value = 1
}

아직까진 별거 없습니다. 여기에 callAsFunction을 하나 붙여볼게요.

struct Grower {
    var value: Int = 1

    mutating func callAsFunction() -> Int {
        value = value * 2
        return value
    }
}

callAsFunctionvalue 프로퍼티를 2배로 늘리고 이 값을 리턴하는 메서드입니다.

이것만 봐도 감이 안 온다면 이어서 아래 코드를 살펴봅시다.

var g = Grower()
g()

위 예제의 마지막 라인에서 g()와 같이 Grower 인스턴스를 함수같이 호출하는 듯한 코드를 실행시켰습니다. 그런데 이게 에러가 안 납니다. 그리고 신기하게도 2를 리턴합니다.

계속 실행시키면 어떻게 될까요?

var g = Grower()
g()
// => 2
g()
// => 4
g()
// => 8
g()
// => 16

네 계속 불어납니다. Grower라는 이름에 어울리나요?

이렇게 callAsFunction은 인스턴스를 직접 호출시키면 호출되는 특수한 메서드입니다. 활용 방법이야 무궁무진하겠지요?

 

728x90
반응형

댓글