Swift5.5の変更点まとめ

## はじめに

これは、Swift5.5で変更が入った機能についてまとめもの。
変更点はCHANGELOG を元に作成した。

https://github.com/apple/swift/blob/main/CHANGELOG.md#swift-55

※ 2021/06/16現在時点のため、まだ変更が入る可能性があります

## Swift5.5のアップデート一覧
- [SE-0296](https://github.com/apple/swift-evolution/blob/main/proposals/0296-async-await.md) Async/await
- [SE-0297](https://github.com/apple/swift-evolution/blob/main/proposals/0297-concurrency-objc.md) Concurrency Interoperability with Objective-C: Objective-Cとの並行処理の相互運用性
- [SE-0298](https://github.com/apple/swift-evolution/blob/main/proposals/0298-asyncsequence.md) Async/Await: Sequences
- [SE-0300](https://github.com/apple/swift-evolution/blob/main/proposals/0300-continuation.md) Continuations for interfacing async tasks with synchronous code: 非同期タスクと同期コードを連動させるための改善
- [SE-0310](https://github.com/apple/swift-evolution/blob/main/proposals/0310-effectful-readonly-properties.md) Effectful Read-only Properties: 副作用のある読み取り専用のプロパティ
- [SE-0311](https://github.com/apple/swift-evolution/blob/main/proposals/0311-task-locals.md) Task Local Values
- [SE-0316](https://github.com/apple/swift-evolution/blob/main/proposals/0316-global-actors.md) Global actors
- [SE-0306](https://github.com/apple/swift-evolution/blob/main/proposals/0306-actors.md) Actors
- [SE-0313](https://github.com/apple/swift-evolution/blob/main/proposals/0313-actor-isolation-control.md) Improved control over actor isolation: アクターのアイソレーションの管理を改善
- [SE-0293](https://github.com/apple/swift-evolution/blob/0c2f85b3ae42539a7cd47fca2473a0bf6f345566/proposals/0293-extend-property-wrappers-to-function-and-closure-parameters.md) Extend Property Wrappers to Function and Closure Parameters: プロパティ・ラッパーを関数やクロージャのパラメータに拡張
- [SE-0299](https://github.com/apple/swift-evolution/blob/main/proposals/0299-extend-generic-static-member-lookup.md) Extending Static Member Lookup in Generic Contexts: Generic ContextsにおけるStatic Member Lookupの拡張

## [SE-0296](https://github.com/apple/swift-evolution/blob/main/proposals/0296-async-await.md) Async/await

`async/await` を使った非同期プログラミングがネイティブにサポートされた。非同期関数は `async` を使って定義できる。

```swift
func loadWebResource(_ path: String) async throws -> Resource { ... }
func decodeImage(_ r1: Resource, _ r2: Resource) async throws -> Image
func dewarpAndCleanupImage(_ i : Image) async -> Image
```

非同期関数の呼び出しはサスペンドする可能性がある。つまり、実行中のスレッドで実行されず、スケジューリングされて後で再実行する。非同期関数を呼び出す場合は、`throws` 関数の呼び出しに `try` を使うことと同様に、`await` が必要。

```swift
func processImageData() async throws -> Image {
  let dataResource  = try await loadWebResource("dataprofile.txt")
  let imageResource = try await loadWebResource("imagedata.dat")
  let imageTmp      = try await decodeImage(dataResource, imageResource)
  let imageResult   = await dewarpAndCleanupImage(imageTmp)
  return imageResult
}
```

`lazy` キーワードがローカルスコープでも機能するようになり以下のように書けるようになった。

```swift
func test(useIt: Bool) {
  lazy var result = getPotentiallyExpensiveResult()
  if useIt {
    doIt(result)
  }
}
```

## [SE-0297](https://github.com/apple/swift-evolution/blob/main/proposals/0297-concurrency-objc.md) Concurrency Interoperability with Objective-C

完了ハンドラブロックを介して非同期に結果を返す `Objective-C` メソッドは、結果を直接返す（またはスローする）非同期メソッドに変換される。
例えば以下の `CloudKit` の `Objective-C` メソッド

```swift
- (void)fetchShareParticipantWithUserRecordID:(CKRecordID *)userRecordID
    completionHandler:(void (^)(CKShareParticipant * _Nullable, NSError * _Nullable))completionHandler;
```

は、`CKShareParticipant` のインスタンスを返す非同期の `throws` メソッドに変換される。

```swift
func fetchShareParticipant(
    withUserRecordID userRecordID: CKRecord.ID
) async throws -> CKShare.Participant
```

Swiftの呼び出し側は、`await` でこの非同期メソッドを呼び出すことができる。

```swift
guard let participant = try? await container.fetchShareParticipant(withUserRecordID: user) else {
    return nil
}
```

## [SE-0298](https://github.com/apple/swift-evolution/blob/main/proposals/0298-asyncsequence.md) Async/Await: Sequences

`for` ループは、非同期コードの非同期シーケンスをトラバースするために使用できる。

```swift
for try await line in myFile.lines() {
  // Do something with each line
}
```

非同期 `for` ループは非同期シーケンスを使用します。これはプロトコル `AsyncSequence` とそれに対応する `AsyncIterator` で定義される。

## [SE-0300](https://github.com/apple/swift-evolution/blob/main/proposals/0300-continuation.md) Continuations for interfacing async tasks with synchronous code

`withUnsafeContinuation` および `withUnsafeThrowingContinuation` 関数を使用して、非同期関数を中断できるようになった。これらの関数はクロージャを受け取り、現在の非同期タスクを中断して、現在のタスクの値を持つクロージャを実行する。プログラムは将来のある時点でその値を使用してタスクを再開し、再開されたタスクの `withUnsafeContinuation` 呼び出しの結果の値またはエラーを渡す必要がある。

```swift
func operation() async -> OperationResult {
  return await withUnsafeContinuation { continuation in
    beginOperation(completion: { result in
      continuation.resume(returning: result)
    }) 
  }
}
```

型名は、メタタイプをパラメータの引数としては使用できなくなった。

```swift
struct MyValue {
}

struct MyStruct {
  subscript(a: MyValue.Type) -> Int { get { ... } }
}

func test(obj: MyStruct) {
  let _ = obj[MyValue]
}
```

`MyValue`がメタタイプを参照するために明示的な`.self`を必要とするため、引数として`MyValue`を引数で受け入れることは見落だった。正しい構文は `obj[MyValue.self]` を使用することになる。

## [SE-0310](https://github.com/apple/swift-evolution/blob/main/proposals/0310-effectful-readonly-properties.md) Effectful Read-only Properties

読み取り専用のプロパティ、`get`と`{`の間にこれらのキーワードの1つまたは両方を記述することで、その`get`を `async` または`throws` に定義できるようになった。これによりメンバは、値を生成する過程で非同期呼び出しやエラーのスローを行うことができるようになった。

```swift
class BankAccount: FinancialAccount {
  var manager: AccountManager?

  var lastTransaction: Transaction {
    get async throws {
      guard manager != nil else { throw BankError.notInYourFavor }
      return await manager!.getLastTransaction()
    }
  }

  subscript(_ day: Date) -> [Transaction] {
    get async {
      return await manager?.getTransactions(onDay: day) ?? []
    }
  }
}

protocol FinancialAccount {
  associatedtype T
  var lastTransaction: T { get async throws }
  subscript(_ day: Date) -> [T] { get async }
}
```

上記の `lastTransaction` のように、メンバーへのアクセスには `await` や `try` を使う必要がある

```swift
extension BankAccount {
  func meetsTransactionLimit(_ limit: Amount) async -> Bool {
    return try! await self.lastTransaction.amount < limit
    //                    ^~~~~~~~~~~~~~~~ this access is async & throws
  }                
}

  
func hadWithdrawlOn(_ day: Date, from acct: BankAccount) async -> Bool {
  return await !acct[day].allSatisfy { $0.amount >= Amount.zero }
  //            ^~~~~~~~~ this access is async
}
```

## [SE-0311](https://github.com/apple/swift-evolution/blob/main/proposals/0311-task-locals.md) Task Local Values

タスクローカル値は、新しい `@TaskLocal` プロパティラッパーを使用して定義できます。このような値は、バインディングが行われたタスクや、子タスク、タスク・コンテキストから作成された非構造化タスクによって暗黙的に伝達されます。

```swift
struct TraceID { 
  @TaskLocal
  static var current: TraceID? 
}

func printTraceID() {
  if let traceID = TraceID.current {
    print("\(traceID)")
  } else {
    print("nil")
  }
}

func run() async { 
  printTraceID()    // prints: nil
  TraceID.$current.withValue("1234-5678") { 
    printTraceID()  // prints: 1234-5678
    inner()         // prints: 1234-5678
  }
  printTraceID()    // prints: nil
}

func inner() {
  // タスクローカル値がバインドされているコンテキストから呼び出された場合、
  // それを表示します（そうでない場合は 'nil' を表示します）。
  printTraceID()
}
```


## [SE-0316](https://github.com/apple/swift-evolution/blob/main/proposals/0316-global-actors.md) Global actors

型を `global actor` として定義することができます。`global actor` は、`actor isolation` の概念を単一のアクター・タイプの外に拡張し、ステートや関数が多くの異なるタイプ、関数、モジュールに分散していても、グローバル・ステート（およびそれにアクセスする関数）が `actor isolation` の恩恵を受けられるようにします。`global actor` は、同時実行プログラムでグローバル変数を安全に扱うことを可能にし、「メイン・スレッド」や「UIスレッド」でのみ実行しなければならないコードなど、その他のグローバルなプログラム制約をモデル化します。新しい `global actor` は、`globalActor` 属性で定義できます

```swift
@globalActor
struct DatabaseActor {
  actor ActorType { }

  static let shared: ActorType = ActorType()
}
```

`global actor` 型は、さまざまな宣言のカスタム属性として使用することができます。これにより、これらの宣言は、`global actor` の共有インスタンスによって記述された `Actor` 上でのみアクセスされるようになります。例えば、以下のようになります。

```swift
@DatabaseActor func queryDB(query: Query) throws -> QueryResult

func runQuery(queryString: String) async throws -> QueryResult {
  let query = try Query(parsing: queryString)
  return try await queryDB(query: query) // 'await' なぜなら、これは暗黙のうちにDatabaseActor.sharedに切り替わるからです。
}
```

 並行ライブラリでは、実行のメインスレッドを表す `MainActor` というグローバルアクターを定義しています。UI の更新など、メイン スレッドで実行する必要があるコードには、このアクターを使用する必要があります。


## [SE-0306](https://github.com/apple/swift-evolution/blob/main/proposals/0306-actors.md) Actors

Swift 5.5には、アクターのサポートが含まれています。アクターは、同時アクセスから保護するためにそのインスタンスデータを分離する新しい種類の型。外部からのアクターへのアクセスは非同期でなければならない。

```swift
actor Counter {
  var value = 0

  func increment() {
    value = value + 1
  }
}

func useCounter(counter: Counter) async {
  print(await counter.value) // 非同期でなければならない
  await counter.increment()  // 非同期でなければならない
}
```

`rethrows` 関数の呼び出しが `throw` できるかどうかの判断は、`Optional` 型のデフォルト引数を考慮するようになった。

Swift 5.4では、そのようなデフォルトの引数は `rethrows` のチェックで完全に無視されていた。

```swift
func foo(_: (() throws -> ())? = nil) rethrows {}
foo()  // no 'try' needed
```

しかしこれでは、`foo()` の呼び出しがスローされる可能性があり、呼び出しサイトが `try` されていないにもかかわらず、以下の例がエラーにならないことを意味する。

```swift
func foo(_: (() throws -> ())? = { throw myError }) rethrows {}
foo()  // 'try' *should* be required here
```

新しい動作としては、最初の例はデフォルトの引数が構文的に `nil` と書かれていて、スローしないことがわかっているのでエラーにならない。2つ目の例は、デフォルトの引数が `can throw` であるため、`try` がないという理由で正しくエラーになる。

## [SE-0313](https://github.com/apple/swift-evolution/blob/main/proposals/0313-actor-isolation-control.md) Improved control over actor isolation

通常は actor-isolated となっているアクター内部の宣言は、nonisolated キーワードを使って明示的に non-isolated とすることができる。
non-isolated は、同期的に呼び出すことができる。

```swift
actor Account: Hashable {
  let idNumber: Int
  var balance: Double

  nonisolated func hash(into hasher: inout Hasher) { // OK、nonisolatedでも同期要件を満たす
    hasher.combine(idNumber) // OK、外側の定数を参照できる
    hasher.combine(balance) // Error、外側の変数は参照できない
  }
}

func test() {
  var hasher = Hasher()
  Account().hash(into: &hasher) // await が必要ない
}
```

アクター型のパラメーターは、`isolated` として宣言することができる。つまり、そのコードが実行時にアクターを表す。`isolated` パラメータは、引数におけるアクターのメソッドの `actor-isolate` セマンティクスを任意の引数に拡張します。

```swift
actor MyActor {
  func f() { }
}

func g(actor: isolated MyActor) {
  actor.f()   // Actor上で実行される
}

func h(actor: MyActor) async {
  g(actor: actor)        // エラー, async で呼び出す必要がある
  await g(actor: actor)  // OK, g を呼び出す前にアクターに切り替わる
}
```


## [SE-0293](https://github.com/apple/swift-evolution/blob/0c2f85b3ae42539a7cd47fca2473a0bf6f345566/proposals/0293-extend-property-wrappers-to-function-and-closure-parameters.md) Extend Property Wrappers to Function and Closure Parameters

関数やクロージャのパラメータにプロパティラッパーを適用できるようになりました。

```swift
@propertyWrapper
struct Wrapper<Value> {
  var wrappedValue: Value

  var projectedValue: Self { return self }

  init(wrappedValue: Value) { ... }

  init(projectedValue: Self) { ... }
}

func test(@Wrapper value: Int) {
  print(value)
  print($value)
  print(_value)
}

test(value: 10)

let projection = Wrapper(wrappedValue: 10)
test($value: projection)
```

コール呼び出し側では、ラップ値または予測値を渡すことができ、`Wrapper` はそれぞれ `init(wrappedValue:)` または `init(projectedValue:)` を使用して初期化されます。

## [SE-0299](https://github.com/apple/swift-evolution/blob/main/proposals/0299-extend-generic-static-member-lookup.md) Extending Static Member Lookup in Generic Contexts

`Self` が完全な具象型に制約されているプロトコル拡張の静的メンバーにアクセスするために、ジェネリクスのコンテキストで型省略を使用することが可能になりました。

```swift
public protocol ToggleStyle { ... }

public struct DefaultToggleStyle: ToggleStyle { ... }

extension ToggleStyle where Self == DefaultToggleStyle {
  public static var `default`: Self { .init() }
}

struct Toggle {
  func applyToggle<T: ToggleStyle>(_ style: T) { ... }
}

Toggle(...).applyToggle(.default)
```

`Self` への参照が、値の型としてのプロトコルや、プロトコル型の値に対するプロトコル・メンバの使用を妨げない場合は、`[Self]`や `[Key : Self]` への参照についても同様に可能になりました。

```swift

protocol Copyable {
  func copy() -> Self
  func copy(count: Int) -> [Self]
}

func test(c: Copyable) {
  let copy: Copyable = c.copy() // OK
  let copies: [Copyable] = c.copy(count: 5) // also OK
}
```