WWDC Quick Look 💓 By SwiftGGTeam
Embrace Swift type inference

Embrace Swift type inference

元の動画を見る

ハイライト

Apple は、Fruta の SwiftUI 検索リストを使用して、Swift の型推論が配列、KeyPath、クロージャー、ViewBuilder からジェネリック パラメーターを推定する方法を示し、Xcode 12 が式エラーをメモと Fix-It を使用して診断に変換する方法を説明します。

主要内容

多くの型情報が呼び出しサイトのコンテキストに隠されているため、SwiftUI コードは短く見えます。リスト、フィルター条件、行ビュー クロージャ (ジェネリック パラメータ、KeyPath、エスケープ クロージャ、および@ViewBuilder。開発者がすべての型を手動で記述した場合、コードは山括弧、型変換、およびクロージャー パラメーターの注釈で埋め尽くされてしまいます。

このセッションにはスムージーアプリ「Fruta」が選ばれました。ホリーはリストに検索を追加したいと考えています。ユーザーが文字列を入力すると、タイトルにその文字列が含まれるスムージーのみがリストに表示されます。彼女はフィルタリング ロジックを直接挿入しませんでした。List、しかし再利用可能なものを書きましたFilteredList、呼び出し元がデータ、フィルタリング プロパティ、フィルタリング関数、および行ビューを渡すことができるようにします。

重要なのはコールポイントです。FilteredList(smoothies, filterBy: \.title, isIncluded: { title in ... }) { smoothie in ... }書かれていないElementFilterKeyRowContent。コンパイラは次から起動しますsmoothiesロールアウトするElement == Smoothie、そしてから\.titleロールアウトするFilterKey == String、最後に後続の ViewBuilder クロージャーから押し出されます。RowContent == SmoothieRowView

Xcode 12 では、型推論エラーが発生した場合の変更もあります。 Swift 5.3 は、統合されたエラー追跡を式内のすべてのエラーに拡張します。コンパイラは推論中に発生した問題を記録し、メモを使用して関連する宣言を示し、fix-it を使用して一般的なエラー (パスの受け渡しなど) を修正します。TextField文字列値をバインディングに変更します。

詳細

1. 呼び出しポイントはコンパイラーに十分な手がかりを残します

(02:56) フルッタのSmoothieList検索語を保存する@State、そしてオリジナルを置きますListと置き換えますFilteredList。この公式コードは、呼び出しサイトをシンプルに保つ方法を示しています。

import SwiftUI

struct SmoothieList: View {
    var smoothies: [Smoothie]

    @State var searchPhrase = ""

    var body: some View {
        FilteredList(
            smoothies,
            filterBy: \.title,
            isIncluded: { title in title.hasSubstring(searchPhrase) }
        ) { smoothie in
            SmoothieRowView(smoothie: smoothie)
        }
    }
}

extension String {
    /// Returns `true` if this string contains the provided substring,
    /// or if the substring is empty. Otherwise, returns `false`.
    ///
    /// - Parameter substring: The substring to search for within
    ///   this string.
    func hasSubstring(_ substring: String) -> Bool {
        substring.isEmpty || contains(substring)
    }
}

キーポイント:

  • smoothies既知のタイプは次のとおりです[Smoothie]、それは与えますElementこの一般的なパラメータが最初の手がかりとなります。 -filterBy: \.title基本型は書き込まれません。Elementすでにコンパイラにこれがであることを知らせていますSmoothie.title
  • isIncluded閉店中titleによるFilterKeyとして発売されましたString, だからあなたは電話することができますhasSubstring
  • トレーリングクロージャーが戻るSmoothieRowView、これはRowContentコンクリートタイプ。 -@State var searchPhrase = ""コンパイラが空の文字列から推論するリテラル推論にも依存します。String

2. 再利用可能なコンポーネントは宣言内に型の関係を記述します

03:53FilteredList宣言では、呼び出しポイントから省略される型の関係を明確に示します。汎用パラメーターは、それぞれデータ要素、フィルター フィールド、行ビューのコンテンツを表します。

import SwiftUI

public struct FilteredList<Element, FilterKey, RowContent>: View
        where Element: Identifiable, RowContent: View {

    private let data: [Element]
    private let filterKey: KeyPath<Element, FilterKey>
    private let isIncluded: (FilterKey) -> Bool
    private let rowContent: (Element) -> RowContent

    public init(
        _ data: [Element],
        filterBy key: KeyPath<Element, FilterKey>,
        isIncluded: @escaping (FilterKey) -> Bool,
        @ViewBuilder rowContent: @escaping (Element) -> RowContent
    ) {
        self.data = data
        self.filterKey = key
        self.isIncluded = isIncluded
        self.rowContent = rowContent
    }

    public var body: some View {
        let filteredData = data.filter {
            isIncluded($0[keyPath: filterKey])
        }

        return List(filteredData, rowContent: rowContent)
    }
}

キーポイント:

  • Elementに制約されていますIdentifiable、最終的には SwiftUI に引き渡されるためList展示する。 -FilterKeyからKeyPath<Element, FilterKey>これにより、コンポーネントが任意のフィールドをフィルターできるようになります。 -isIncluded引き継ぐFilterKeyそして戻るBoolの場合、呼び出しポイントは「このフィールドの値が保持されるかどうか」を記述するだけで済みます。 -rowContent引き継ぐElementそして戻るRowContentwhere RowContent: View戻り値が SwiftUI ビューになれることを確認します。 -@ViewBuilderコール ポイントで SwiftUI DSL 構文を使用すると、ViewBuilder はクロージャ内の子ビューを親ビューに必要な構造に収集します。

3. 型推論は制約を解くようなものであり、型を推測するものではありません

(08:43) このトークでは、型推論をパズルとして説明しています。コンパイラは最初に検索しますsmoothies、クイック ヘルプで知られています。[Smoothie]、それですべてElementプレースホルダーを次のように置き換えますSmoothie。この結果により、\.titleなるSmoothie.title, クイックヘルプでそれが示されていますString、それからFilterKeyなるString。最後に、ViewBuilder クロージャには 1 つだけあります。SmoothieRowView、それでRowContentなるSmoothieRowView

このシーケンスは、呼び出しサイトを記述する必要がない理由を説明しています。

// これらの型は呼び出しサイトのコンテキストから手がかりが得られるため、実際のコードで手書きする必要はありません。
Element == Smoothie
FilterKey == String
RowContent == SmoothieRowView

キーポイント:

  • コンパイラーは既存の型から推論を開始し、新しい結論がその後の手がかりを解き明かし続けます。 -Element特定されると、すべての出来事がElementすべての場所で同じコンクリート タイプが使用されます。 -FilterKeyソースはKeyPath指定された属性の型、クロージャー パラメーター名は、この推論された型を継承するだけです。 -RowContentViewBuilder クロージャからの結果の型。
  • プレースホルダーに手がかりが一致しない型で埋められている場合、推論は完了できず、ソース コードにエラーが発生します。

4. Xcode 12 は推論の失敗を追跡可能な診断に変換します

(11:31、[14:00](https://developer.apple.com/vi deos/play/wwdc2020/10165/?time=840)、 15:46) キー パスが間違った属性に書き込まれた場合、コンパイラはFilterKey所定の位置に押し込みますBool。次isIncludedクロージャで呼び出されるhasSubstring時間、Boolこのメソッドを使用しないと、式は失敗します。

Xcode 12 の改良点がここにあります。 Swift コンパイラーは、型推論中のエラーをログに記録し、ヒューリスティックを使用して推論を継続し、最後に収集したエラー、修正、メモをレポートします。スピーチの具体例は次の 2 つです。TextFieldコンパイラによって提供されるバインディングが必要です$参照バインディングの修正。Smoothie満たさないIdentifiable、メモに戻ります。FilteredList宣言する、参照where Element: Identifiableこの制約。

public struct FilteredList<Element, FilterKey, RowContent>: View
        where Element: Identifiable, RowContent: View

キーポイント:

  • Identifiable制約はそこにはありませんSmoothieListコールポイントでは通知されますが、メモを通じて返されますFilteredList声明。
  • コンパイラーによって記録された推論された具象型が診断に表示されます。たとえば、Element押し込まれたSmoothie
  • Issue Navigator は、プロジェクト全体のビルドの失敗を表示するのに適しています。 Option+Shift をクリックしてメモをクリックすると、関連ファイルが並べて開きます。
  • クイック ヘルプでは、次のような特定のパラメータの推定タイプを確認できます。\.title対応するString
  • 空の文字列を使用し、"Berry"2 セットの検索語によりキャンバスが更新され、フィルタリング ロジックが実際に推測された型に従って動作することが確認されます。

重要ポイント

1. 入力された検索リストを作成する

何をすべきか: リスト検索を類似のものに抽出します。FilteredList呼び出し元が配列、フィルター フィールド、フィルター条件、行ビューを渡すことができる再利用可能な SwiftUI コンポーネント。

実行する価値がある理由: セッション ショーElementFilterKeyRowContent呼び出し元が SwiftUI ネイティブに近い状態を維持できるように、呼び出しポイントから自動的に推論する方法List書き方。

開始方法: まずは質問してくださいElement: Identifiable、フィールドエントリを次のように設計します。KeyPath<Element, FilterKey>、フィルター クロージャは次のように記述されます。(FilterKey) -> Bool、行閉鎖プラス@ViewBuilder

2. チームコンポーネントのより明確な一般的な境界を設計する

対処方法: SwiftUI の内部コンポーネントを調べて、「呼び出しサイトで記述する型」と「宣言で表現される型の関係」を分離します。

そうする価値がある理由: スピーチでのコールポイントが簡潔である理由は次のとおりです。FilteredList初期化パラメータは、データ、KeyPath、フィルタ クロージャ、および行クロージャ間の関係を完全に表現します。

開始方法: 繰り返しビュー コンポーネントから始めて、実際に必要な 3 つのタイプ (入力データ、構成に使用されるフィールド、最終的に生成されるビュー) をリストします。次に、これらの型を汎用パラメータに入れて、where制約。

3. コンパイラ ノートをデバッグ プロセスに組み込む

やるべきこと: Swift ビルドの失敗処理の一連の習慣を確立します。Issue Navigator を開き、最初に fix-it を確認し、次にメモで示されている宣言ファイルを確認します。

実行する価値がある理由: Swift 5.3 と Xcode 12 では、式の型推論でより多くのエラー コンテキストがログに記録され、「この制約が現在の呼び出しサイトに関連する理由」を説明するメモが付けられます。

開始方法: Xcode の動作でビルドが失敗した場合の問題ナビゲーターを設定します。一般エラーまたは SwiftUI エラーが発生した場合は、Option+Shift を使用してメモで示された場所を開き、呼び出しポイントに戻って問題を修正します。

4. 型推論後にプレビューを使用して実際のパスを上書きします

何をすべきか: 空の検索用語や ViewBuilder など、ジェネリックスと ViewBuilder に依存するコンポーネントの SwiftUI プレビューの複数のセットを補足します。"Berry"検索語。

実行する価値がある理由: 最後に、セッションはプレビュー プロバイダーを使用して 2 セットの検索フレーズを同時に実行して検証します。FilteredList推論された型、フィルター関数、および rowContent クロージャーは正しく連携して機能します。

開始方法: プレビュー プロバイダー用の一連の固定入力を準備し、主要な状態を列挙し、内部ロジックをテストするために呼び出しポイントを個別にバイパスするのではなく、状態ごとにコンポーネントの実際の初期化子を 1 回実行します。

関連セッション

  • Swift の新機能 — 言語、診断、ランタイム、開発エクスペリエンスに対する Swift 5.3 の同年のアップデートについて説明します。
  • SwiftUI のアプリの要点 — ここで SwiftUI ビューの組み合わせを完全なアプリ、シーン、WindowGroup 構造に組み込みます。
  • SwiftUI の新機能 — ジェネリックス、クロージャ、ViewBuilder に依存する SwiftUI 2020 呼び出しサイトをもっと見る。
  • SwiftUI の概要 — 宣言型ビューの構成の基本に立ち返り、SwiftUI がなぜこれほど多くの型推論を必要とするのかを理解します。

コメント

GitHub Issues · utterances