WWDC Quick Look 💓 By SwiftGGTeam
What's new in Swift

What's new in Swift

元の動画を見る

ハイライト

Swift 5.5 では、async/await、構造化同時実行性、アクターが導入され、Swift Collections、Swift Algorithms、Swift System、DocC などのツールを通じて、パッケージ エコロジー、ドキュメント、ビルド パフォーマンス、日常の構文の開発エクスペリエンスが補完されます。

主要内容

多くの Swift プロジェクトの問題点はビジネス コードではなく、周辺コードにあります。

サードパーティのパッケージを見つけるには、まず Web を検索し、次に Git URL を Xcode にコピーします。標準ライブラリには、両端キュー、順序付きセット、順序付き辞書はありません。チームは、それらを自分たちで作成するか、さまざまなソースから実装を導入することしかできません。システム コールを行う場合、低レベル インターフェイスは C に近く、型安全性とクロスプラットフォーム エクスペリエンスは十分自然ではありません。

非同期コードの方が一般的です。ネットワークリクエストは次のように分割されます。dataTask、完了ハンドラー、エラーパラメータ、resume()。本当のビジネスプロセスはクロージャの中に隠されています。書きたいですかtry/catchただし、すべてのエラーをコールバックに詰め込む必要があります。

Swift 5.5 は 2 つのことを行います。

まず、Apple は Swift エコシステムを拡大しました。 Xcode 13 は Swift パッケージ コレクションをサポートしており、Swift の公式オープン ソース パッケージにはコレクション、アルゴリズム、システム、数値などの新機能が追加されています。 DocC は Xcode に入り、Markdown アノテーションを使用してフレームワーク ドキュメントを生成します。 Swift Driver がデフォルトのコンパイルドライバーとなり、増分インポートによりモジュール変更後の再コンパイルの範囲が減ります。

次に、Swift 言語には新しい同時実行モデルが追加されています。async機能を一時停止できることを示します。await吊り下げるポイントをマークし、async let関連するタスクを並行して実行します。actorコンパイラとランタイムを使用して、共有可変状態へのアクセスを調整します。

結果は簡単です。ネットワーク リクエストを記述するとき、コードは上から下に実行されます。並列レンダリングを作成する場合、サブタスクは親関数をエスケープしません。統計カウンターを書き込むとき、アクターは同時アクセスをキューに入れて、複数のスレッドが同時に同じ値を変更するのを防ぎます。

詳細

Swift コレクション: 標準ライブラリ外の共通データ構造

(06:16) Swift Collections は、標準ライブラリの不足しているデータ構造を補う新しいオープンソース パッケージです。初版の収録内容DequeOrderedSetOrderedDictionary

Deque配列と似ていますが、両端で効率的な挿入と削除をサポートします。

import Collections

var colors: Deque = ["red", "yellow", "blue"]

colors.prepend("green")
colors.append("orange")
// `colors` is now ["green", "red", "yellow", "blue", “orange"]

colors.popFirst() // "green"
colors.popLast() // "orange"
// `colors` is back to ["red", "yellow", "blue"]

キーポイント:

  • import CollectionsSwift Collections パッケージの紹介。
  • var colors: Deque = [...]両端キューを作成します。
  • colors.prepend("green")キューの先頭に要素を挿入します。
  • colors.append("orange")キューの最後に要素を挿入します。
  • colors.popFirst()キューの先頭から要素を削除して返します。
  • colors.popLast()キューの最後から要素を削除して返します。

06:25OrderedSet秩序と独自性を保ちながら。配列と同様に添字アクセスをサポートし、セットと同様に要素が 1 回だけ出現することを保証します。

import Collections

var buildingMaterials: OrderedSet = ["straw", "sticks", "bricks"]

for i in 0 ..< buildingMaterials.count {
    print("Little piggie #\(i) built a house of \(buildingMaterials[i])")
}
// Little piggie #0 built a house of straw
// Little piggie #1 built a house of sticks
// Little piggie #2 built a house of bricks

buildingMaterials.append("straw") // (inserted: false, index: 0)

キーポイント:

  • OrderedSet広告掲載オーダーを保存します。
  • buildingMaterials.count要素の数を返します。
  • buildingMaterials[i]要素を順番に読み取ります。
  • append("straw")既存の要素を挿入してみてください。
  • 戻り値内inserted: false新しい要素が挿入されないことを示します。index: 0既存の要素の位置を示します。

06:42OrderedDictionaryHTTP ステータス コードのリストを表示するなど、キーと値のペアの安定した順序が必要なシナリオに適しています。

import Collections

var responses: OrderedDictionary = [200: "OK", 403: "Forbidden", 404: "Not Found"]

for (code, phrase) in responses {
    print("\(code) (\(phrase))")
}
// 200 (OK)
// 403 (Forbidden)
// 404 (Not Found)

キーポイント:

  • OrderedDictionaryキーと値のペアの順序を保存します。
  • リテラル[200: "OK", ...]初期コンテンツを作成します。
  • for (code, phrase) in responsesキーと値を保存された順序で繰り返します。
  • printステータスコードと理由フレーズを出力します。

Swift アルゴリズムと Swift システム: 共通のアルゴリズムとシステム コールを Swift API に作成します

(07:39) Swift Algorithms は、シーケンス アルゴリズムとコレクション アルゴリズムを提供する新しいオープン ソース パッケージです。講演では、組み合わせ、順列、グループ化、最小値、最大値、ランダムサンプリングなど、40を超えるアルゴリズムが追加されたと述べた。

import Algorithms

let testAccounts = [ ... ]

for testGroup in testAccounts.uniquePermutations(ofCount: 0...) {
    try validate(testGroup)
}

let randomGroup = testAccounts.randomSample(count: 5)

キーポイント:

  • import AlgorithmsSwift アルゴリズム パッケージの紹介。
  • testAccounts.uniquePermutations(ofCount: 0...)指定された範囲の数値の一意の順列を生成します。
  • for testGroup in ...生成されたテストの組み合わせを 1 つずつ検証します。
  • try validate(testGroup)検証プロセスでエラーがスローされた可能性があることを示します。
  • randomSample(count: 5)セットからランダムに 5 つの要素を選択します。

(07:52) Swift System は、Swift の習慣により沿った低レベルのシステム コール インターフェイスを提供します。 Apple プラットフォーム、Linux、Windows をサポートします。

import System

let fd: FileDescriptor = try .open(
    "/tmp/a.txt", .writeOnly,
    options: [.create, .truncate], permissions: .ownerReadWrite)
try fd.closeAfter {
    try fd.writeAll("Hello, WWDC!\n".utf8)
}

キーポイント:

  • import SystemSwift システムパッケージの紹介。
  • FileDescriptorタイプを使用してファイル記述子を表します。
  • .open("/tmp/a.txt", .writeOnly, ...)書き込み専用にファイルを開きます。
  • options: [.create, .truncate]存在しない場合は作成します。存在する場合は切り捨てられます。
  • permissions: .ownerReadWrite所有者の読み取りおよび書き込み権限を設定します。
  • fd.closeAfter { ... }クロージャが実行された後、ファイル記述子を閉じます。
  • fd.writeAll("Hello, WWDC!\n".utf8)UTF-8 バイトを書き込みます。

08:06FilePath新しいパス操作 API が追加され、拡張子のクエリと設定、コンポーネントの追加、コンポーネントの削除、パスの正規化の実行が可能です。

import System

var path: FilePath = "/tmp/WWDC2021.txt"
print(path.lastComponent)         // "WWDC2021.txt"

print(path.extension)             // "txt"
path.extension = "pdf"            // path == "/tmp/WWDC2021.pdf"
path.extension = nil              // path == "/tmp/WWDC2021"
print(path.extension)             // nil

path.push("../foo/bar/./")        // path == "/tmp/wwdc2021/../foo/bar/."
path.lexicallyNormalize()         // path == "/tmp/foo/bar"
print(path.ends(with: "foo/bar")) // true!

キーポイント:

  • FilePathSwift タイプを使用してファイル パスを表します。
  • path.lastComponent最後のパスコンポーネントを読み取ります。
  • path.extension拡張機能を読み取ります。
  • path.extension = "pdf"拡張子を変更します。
  • path.extension = nil拡張機能を削除します。
  • path.push("../foo/bar/./")パスコンポーネントを追加します。
  • path.lexicallyNormalize()標準化する..そして.
  • path.ends(with: "foo/bar")パスの終点を確認してください。

Swift 5.5 構文の改善: コード化可能、静的メンバー検索、パラメーター プロパティ ラッパー

(17:04) 過去には、関連する値を持つ列挙が実装されていましたCodable、手書きする必要がありますinit(from:)encode(to:)そして複数のグループCodingKey。 Swift 5.5 はコンパイラで合成できます。

enum Command: Codable {
    case load(key: String)
    case store(key: String, value: Int)
}

キーポイント:

  • enum Commandコマンドの種類を定義します。
  • : Codableエンコードとデコードをサポートすることを宣言します。
  • case load(key: String)関連する値付き。
  • case store(key: String, value: Int)2 つの関連する値。
  • コンパイラは、これらの場合に備えてエンコードおよびデコード ロジックを生成します。

(17:26) 型推論により、列挙値を呼び出すときに型名を省略できます。 Swift 5.5 では、静的メンバーの検索機能が拡張され、プロトコルの静的プロパティも列挙型の API を形成できるようになりました。

enum Coffee {
    case regular
    case decaf
}

func brew(_ coffee: Coffee) { ... }

brew(.regular)

キーポイント:

  • enum Coffeeコーヒーの種類を定義します。
  • case regularそしてcase decaf列挙メンバーです。
  • func brew(_ coffee: Coffee)パラメータのタイプは明示的にCoffee
  • brew(.regular)型推論による省略Coffee.regular

(18:25) プロパティ ラッパー (Property Wrapper) は、もともとプロパティによく使用されていました。 Swift 5.5 では、SE-0293 を介してこれを関数パラメータおよびクロージャ パラメータとともに使用できます。

@propertyWrapper
struct NonEmpty<Value: Collection> {
    init(wrappedValue: Value) {
        precondition(!wrappedValue.isEmpty)
        self.wrappedValue = wrappedValue
    }

    var wrappedValue: Value {
        willSet { precondition(!newValue.isEmpty) }
    }
}

func logIn(@NonEmpty _ username: String) {
    print("Logging in: \(username)")
}

キーポイント:

  • @propertyWrapper声明NonEmptyプロパティラッパーです。
  • Value: Collectionラップされた値はコレクション型でなければならないという制限。
  • init(wrappedValue:)初期化中にコレクションが空でないことを確認してください。
  • precondition(!wrappedValue.isEmpty)Null 値が渡されると、実行時チェックの失敗がトリガーされます。
  • wrappedValue真の値を保存します。
  • willSet新しい値を変更する前に、その値が空でないことを確認してください。
  • func logIn(@NonEmpty _ username: String)同じ制約セットを関数パラメーターに適用します。

SwiftUI コードの短縮: バインドされた配列、ドット構文、CGFloat 変換

(19:37) この講演では、設定リストを使用して、毎日の SwiftUI コードに対する Swift 5.5 の影響を示します。以前は、配列内のバインディングにアクセスするには添字を使用する必要があり、また明示的に次のように記述する必要がありました。CheckboxToggleStyle()そしてCGFloat(padding)。バインディング配列を直接渡すことができるようになりました。

// You can now write this.

import SwiftUI

struct SettingsView: View {
    @State var settings: [Setting]

    private let padding = 10.0

    var body: some View {
        List($settings) { $setting in
            Toggle(setting.displayName, isOn: $setting.isOn)
              #if os(macOS)
              .toggleStyle(.checkbox)
              #else
              .toggleStyle(.switch)
              #endif
        }
        .padding(padding)
    }
}

キーポイント:

  • @State var settings: [Setting]変更可能な設定の配列を保存します。
  • List($settings)設定配列のプロジェクション バインディングをリストに渡します。
  • { $setting in ... }クロージャは各要素のバインディングを直接取得します。
  • Toggle(setting.displayName, isOn: $setting.isOn)同時に表示名を読み取り、スイッチのステータスをバインドします。
  • #if os(macOS)同じコード部分でプラットフォームごとにスタイルを選択します。
  • .toggleStyle(.checkbox)簡略化された静的メンバーのドット構文を使用します。
  • .padding(padding)コンパイラに依存するDoubleそしてCGFloatの間で変換します。

async/await: コールバック ネットワーク リクエストをシーケンシャル コードに変更する

(22:20) 以前に使用されましたURLSession.dataTaskリクエストを行うと、関数が最初に戻り、実際のデータ処理はクロージャで発生します。エラーは追加のパラメーターを通じても渡されます。

// Instead of writing this...

func fetchImage(id: String, completion: (UIImage?, Error?) -> Void) {
    let request = self.imageURLRequest(for: id)
    let task = URLSession.shared.dataTask(with: request) {
        data, urlResponse, error in
        if let error = error {
            completion(nil, error)
        } else if let httpResponse = urlResponse as? HTTPURLResponse,
                httpResponse.statusCode != 200 {
            completion(nil, MyTransferError())
        } else if let data = data, let image = UIImage(data: data) {
            completion(image, nil)
        } else {
            completion(nil, MyOtherError())
        }
    }
   task.resume()
}

キーポイント:

  • completion: (UIImage?, Error?) -> Voidコールバックを使用して成功値またはエラーを返します。
  • URLSession.shared.dataTask(with: request)非同期タスクを作成します。
  • リクエストが完了した後にクロージャが受信されますdataurlResponseerror
  • エラー分岐ごとに呼び出されますcompletion(nil, ...)
  • ブランチコールの成功completion(image, nil)
  • task.resume()タスクを開始します。

(24:40) Swift 5.5URLSession.shared.data(for:)一緒にいることができますtry await一緒に使用されます。関数シグネチャ宣言async throws、エラーは Swift の独自のスローメカニズムに入ります。

// You can now write this.

func fetchImage(id: String) async throws -> UIImage {
    let request = self.imageURLRequest(for: id)
    let (data, response) = try await URLSession.shared.data(for: request)
    if let httpResponse = response as? HTTPURLResponse,
       httpResponse.statusCode != 200 {
        throw TransferFailure()
    }
    guard let image = UIImage(data: data) else {
        throw ImageDecodingFailure()
    }
    return image
}

キーポイント:

  • async throws -> UIImage関数がハングするかエラーをスローし、成功すると画像を返すことを示します。
  • let request = self.imageURLRequest(for: id)リクエストを作成します。
  • try await URLSession.shared.data(for: request)リクエストを行って結果を待ちます。
  • let (data, response)返されたデータと応答メタデータを分解します。
  • HTTPURLResponse分岐チェックのステータスコード。
  • throw TransferFailure()呼び出し元への送信エラーを処理します。
  • guard let image = UIImage(data: data)画像をデコードします。
  • return image最終結果を返します。

構造化された同時実行性: 並列タスクを親関数によって制約します。

(27:06) 一部のタスクは並列実行できます。この例では、背景画像と前景画像を同時にレンダリングしたり、タイトル画像を別々にレンダリングしたり、最後に 3 つの結果を結合したりできます。

func titleImage() async throws -> Image {
    async let background = renderBackground()
    async let foreground = renderForeground()
    let title = try renderTitle()
    return try await merge(background,
                           foreground,
                           title)
}

キーポイント:

  • func titleImage() async throws -> Imageエラーの一時停止とスローをサポートする関数を宣言します。
  • async let background = renderBackground()背景画像のレンダリングタスクを開始します。
  • async let foreground = renderForeground()フォアグラウンド レンダリング タスクを開始します。
  • let title = try renderTitle()現在のプロセスでタイトル マップを生成します。
  • try await merge(...)マージする前に、並列結果の準備ができるまで待ちます。
  • async letサブタスクは次の値を超えることはできませんtitleImage()ライフサイクル。
  • 関数内でエラーがスローされると、ランタイムは未完了のタスクを待機し、早期完了の信号を送信します。

アクター: 共有された可変状態を隔離します

(29:26) 複数のスレッドが同じカウンターを同時に変更すると、結果が破損する可能性があります。 Swift 5.5 アクターでは、この種の状態を同時実行安全な参照型によって管理できます。

actor Statistics {
    private var counter: Int = 0
    func increment() {
        counter += 1
    }
    func publish() async {
        await sendResults(counter)
    }
}

var statistics = Statistics()
await statistics.increment()

キーポイント:

  • actor Statistics俳優を定義します。
  • private var counter: Int = 0保護された可変状態を保存します。
  • func increment()アクター内のカウンターを変更します。
  • func publish() async結果のパブリッシュ中にステートメントがハングする可能性があります。
  • await sendResults(counter)ネットワークおよびその他の非同期操作が完了するまで待ちます。
  • var statistics = Statistics()アクターインスタンスを作成します。
  • await statistics.increment()アクターの外部からメソッドを呼び出すときに使用されますawait
  • アクターは、データ破損を引き起こす可能性のある操作の前に呼び出しを一時停止し、安全に実行できるようになるまで待機します。

重要ポイント

  • 何をすべきか: イメージ リスト用の非同期/待機ネットワーク読み込みレイヤーを作成します。 実行する価値がある理由:URLSession.shared.data(for:)リクエスト、ステータスコードチェック、ピクチャデコードを順番に書けばエラーはなくなるthrows開始方法: 古い完了ハンドラーを次のように変更します。func fetchImage(id:) async throws -> UIImage、ビューモデルで使用されますtry await電話。

  • やるべきこと: チャット、通知、またはログ ページの順序付けされた重複排除リストを維持します。 実行する価値がある理由:OrderedSet順序を保持し、要素が一意であり、「到着順に表示されるが繰り返されない」データに適していることを確認します。 始め方: はじめにCollections、使用OrderedSetメッセージ ID または通知 ID を保存し、添字順にリストを表示します。

  • 何をすべきか: テスト システム用に、より体系的なアカウントの組み合わせを生成します。 実行する価値がある理由: Swift Algorithms は、手書きサイクルを減らすために、順列、組み合わせ、ランダム サンプリングなどの一連のアルゴリズムを提供します。 始め方: はじめにAlgorithms、使用uniquePermutations(ofCount:)テストアカウントの組み合わせを列挙するには、次を使用します。randomSample(count:)サンプリング検証を行います。

  • 作業内容: ポイント数、ダウンロードの進行状況、同期ステータスをアクターにカプセル化します。 実行する価値がある理由: アクターは、スピーチ内で複数のタスクによる同時アクセスに適した変数状態です。Statisticsこれは反例です。 開始方法: 原稿を入れますclass Statisticsに変更しますactor Statistics、変数属性を次のように設定します。private, 外部から電話をかける場合に追加します。await

  • 内容: 内部ツールまたは Swift パッケージ用の公開可能なドキュメントを生成します。 実行する価値がある理由: DocC は Xcode 13 に統合されており、Swift ソース コードの Markdown コメントを使用してドキュメントを生成します。 開始方法: まず、Markdown コメントをパブリック型に追加し、次に Xcode の DocC ワークフローを使用してドキュメント アーカイブを生成します。

関連セッション

コメント

GitHub Issues · utterances