티스토리 뷰

Swift

Swift 5.4 Released!

Zedd0202 2021. 4. 28. 22:06
반응형

 

안녕하세요 :) Zedd입니다.

4월 26일에 Swift 5.4가 릴리즈 됐네요.

Xcode 12.5 Beta Release Notes 📝의 Swift > New feature부분에서 다루긴 했는데,

안본것도 있고 그러니 호다닥 공부해보겠습니다.

 

Swift 5.4는 다음과 같은 새로운 언어 feature가 포함됩니다.

- functions, subscripts, initializers에서 multiple variadic parameters 지원.

- implicit member syntax확장 

- Result builders 

- overloading을 지원하는 Local functions(지역 함수) 

- local variables(지역 변수)에 대한 Property wrappers

 

# [SE-0284] functions, subscripts, initializers에서 multiple variadic parameters 지원.

func foo(_ a: Int..., b: Double...) { }

struct Bar {
  subscript(a: Int..., b b: Int...) -> [Int] { a + b }

  init(a: String..., b: Float...) { }
}

원래

single variadic parameter만 가능했고, 한개 이상하려고 하면 위와같은 오류가 났는데 

Swift 5.4에서는 레이블만 달려있으면

1개 이상의 variadic parameter가 가능하다.

 

# [SE-0287] implicit member syntax확장 

Swift 5.4에서는 다음 코드가 유효한것으로 판단.

let milky: UIColor = .white.withAlphaComponent(0.5)
let milky2: UIColor = .init(named: "white")!.withAlphaComponent(0.5)
let milkyChance: UIColor? = .init(named: "white")?.withAlphaComponent(0.5)

SwiftUI의 경우

Text("Hello, world!")
            .foregroundColor(.red.opacity(0.5))

이런게 가능해지는 것.

원래

Text("Hello, world!")
            .foregroundColor(Color.red.opacity(0.5))

이렇게 Color라고 꼭 써줘야됐음.

+ Swift 5.4이전에서도 당연히

Text("Hello, world!")
            .foregroundColor(.red)

이거는 된다. 체이닝이 안됐던 것 뿐.

 

# [SE-0289] Result builder

이건 잘 이해가 안가니 나중에 따로 글을...

 

# [SR-10069] overloading을 지원하는 Local functions(지역 함수) 

💡 overloading(오버로딩) : 같은 이름의 메서드 여러개를 가지면서 매개변수의 타입과 개수가 다르도록 하는 기술

ƒ라는 함수 안에서 nested라는 이름을 가진 지역 함수 2개를 작성.

이름은 같지만 파라미터 타입이 다르므로 오버로딩이 사용(?)되었다고 할 수 있다. 

Swift 5.4이전 - 컴파일에러

Swift 5.4이후 - OK!

 

# local variables(지역 변수)에 대한 Property wrappers

Property wrapper에 대한 내용은 Property Wrapper 글 참고.

(위 글에 대한 예제를 그대로 사용하겠음)

@propertyWrapper
struct Uppercase {
    
    private var value: String = ""
    
    var wrappedValue: String {
        get { self.value }
        set { self.value = newValue.uppercased() }
    }
    
    init(wrappedValue initialValue: String) {
        self.wrappedValue = initialValue
    }
}

이런 로직들을 Property wrapper로 만들고,

struct Address {
    @Uppercase var town: String
}

이런식으로 사용이 가능했음.

하지만

func f() {
    @Uppercase let town: String
}

이렇게 지역변수로 Property wrapper를 만들면

local variables은 아직 Property wrapper를 지원안한다고 컴파일에러.

Swift 5.4부터는 이것도 가능

 

# Runtime Performance and Code Size Improvements

1. Swift 5.4에서는 previous lookup 결과를 캐싱하기 위해 더 빠른 Hash Table구현

→ 프로토콜 적합성 검사가 훨씬 빨라짐

→ 공통 런타임 as? 과 as! casting operations 속도가 높아짐 

 

2. 연속적인(consecutive) Array 수정은 중복된 고유성 검사를 방지한다.

func foo(_ a: inout [Int]) {
  // copy-on-write (CoW) 체크를 여기서 반드시 한다. 
  a[0] = 1
  // 컴파일러는 여기서 중복 COW검사를 생성하지 않음. 
  a[1] = 2
}

 

3. 다양한 성능 향상

- 문자열 보간(String interpolations)은 보다 적극적으로 일정하게 접힌다..? (more aggressively constant-folded)

- inout 함수 argument 및 루프 내에서 retain/release 호출 감소

- 표준 라이브러리의 일반 메타 데이터는 이제 컴파일 타임에 specialize되어 dirty memory사용량을 줄이고 성능을 향상시킨다.

 

# Build Performance

1. Swift 컴파일러는 파일간의 종속성을 추적하는데 훨씬 더 뛰어나졌음

→ 증분 빌드 중에 여러 종류의 변경사항에 대해 컴파일 된 파일 수가 크게 감소.

 

2. 이제 멤버 변수 및 구조체, 열거형, 클래스 및 프로토콜의 함수에 대한 종속성은 Swift 컴파일러에 의해 개별적으로 추적됨 

→ 이러한 엔티티 변경 후 rebuilds 속도가 빨라지고 축소된다? (shrinks)

 

3. 증분 빌드는 더 많은 경우에 deterministic products를 생산한다..(Incremental builds produce deterministic products in many more cases. 이건 뭔소린지 모르겠음)

 

# Code Completion

- Code Completion의 성능은 큰 함수 본문(large function bodies)에서 훨씬 빨라졌음.

swift-package-manager repository 한 예제에서 self. 에 대한 Code Completion은 Swift 5.3에 비해 4배 빨라짐(20ms → 4ms) 

- Code Completion은 오류가 포함된 expressions과 추가 context가 없는 모호한(ambiguous) 식에서도 더욱 안정적이 됨.

func test(a: Int, b: String) -> Int { ... }
func test(a: Int, b: Int) -> String { ... }
func test(a: (Int, Int) -> Int) -> Int { ... }

위 코드의 경우 

test().prefix(3). 후 code completion은 String멤버를 제안.

test(a: 2).  후 code completion은 Int 및 String 멤버를 제안.

test { $0. } 후 $0. code completion은 블록에서 Int멤버를 제안.

 

# Type Checker

1. Swift 5.4는 a + b + (2 *c)와 같은 "연결된" expressions에 대한 타입 검사 성능을 향상.

ex. 

struct S { var s: String? }

func test(_ a: [S]) {
   _ = a.reduce("") {
     ($0 + "," + ($1.s ?? "")) + ($1.s ?? "") + ($1.s ?? "")
   }
}

위 코드의 경우 원래는 시간 초과가 떴지만, 

(이렇게)

Swift 5.4컴파일러에서는 100ms이내에 완료된다고 함.

 

2. Type Checker는 다른 리터럴 표현식을 포함하는 중첩된 배열 리터럴에 대한 성능을 개선.

ex.

enum E {
  case first
  case second
  case third
}

let dictionary = [
  .first: [0, 1, 2, 3, 4, 5, 6, 7],
  .second: [8, 9, 10, 11, 12, 13, 14, 15],
  .third: [16, 17, 18, 19, 20, 21, 22, 23],
]

위 코드의 경우에는 사실 컴파일에러가 떠야함. 왜냐? enum E에 대한 추론을 할 수 없기 때문

하지만 그런 에러는 안뜨고 “too complex to solve in reasonable time”라는 메세지가 뜬다. 

(이렇게)

Swift 5.4에서는 정확한 오류메세지와 함께 코드를 유효하지 않은 것으로 진단함.

error: reference to member 'first' cannot be resolved without a contextual type
.first : [ 0, 1, 2, 3, 4, 5, 6, 7],
 ^
error: reference to member 'second' cannot be resolved without a contextual type
 .second : [ 8, 9, 10, 11, 12, 13, 14, 15],
 ^
error: reference to member 'third' cannot be resolved without a contextual type
 .third : [16, 17, 18, 19, 20, 21, 22, 23],
 ^

 

3. Type checker가 잘못된 statements(e.g. invalid return statement), 잘못된 선언 참조 및 패턴 일치 오류를 포함하여 결과 빌더에 대한 진단 개선

import SwiftUI

struct ContentView: View {
  @State private var condition = false

  var body: some View {
    Group {
      if condition {
        Text("Hello, World!")
          .frame(width: 300)
      } else {
        return Text("Hello, World!")
      }
    }
  }
}

위 코드의 경우 

이런 에러가 떴지만, Swift 5.4 컴파일러에서는

error: cannot use explicit 'return' statement in the body of result builder 'SceneBuilder'
 return Text("Hello, World!")

정확한 오류를 보고하게 됨.

 

# Debugging

Apple 플랫폼에서 Swift 코드를 디버깅 할 때 resilient type(탄력적인 타입. URL, URLComponents, Notification, IndexPath, Decimal, Data, Date, Global, Measurement, UUID를 포함한 Foundation value types)을 가진 변수가 Xcode variable view 와 frame variable에 표시됨. 

 

 

참고

swift.org/blog/swift-5-4-released/

반응형

'Swift' 카테고리의 다른 글

Swift 5.5 ) Codable synthesis for enums with associated values  (0) 2021.11.18
WWDC 21 ) What‘s new in Swift  (3) 2021.06.11
Introducing Swift Collections  (0) 2021.04.13
dynamicCallable  (0) 2021.03.18
dynamicMemberLookup  (0) 2021.03.11