The Missing Manual
For Swift Development

The Guide私が始めたときに持っていたかったガイドの無料コピーをダウンロードしてください

Swift開発について学ぶ20,000人以上の開発者に参加

無料のコピーをダウンロード

これを見ているなら、Swift拡張機能に精通していると思います。 Swift拡張機能を使用すると、型、クラス、構造体、列挙型、またはプロトコルに機能を追加できます。 しかし、拡張機能はそれよりも強力です。 このエピソードでは、Swift拡張機能の4つの巧妙な使用法をお見せしたいと思います。

プロトコル準拠

Swiftプログラミング言語は、拡張機能を使用して既存のタイプをプロトコルに準拠させることができると述べています。 これは新しいものでも革命的なものでもありませんが、コードを整理しておくのにも役立ちます。

例としてUITableViewDataSourceUITableViewDelegateプロトコルを取ります。 この例は見覚えがあるかもしれません。 これは問題ありませんが、クラスの実装が長くなり、時間の経過とともにナビゲートが困難になる可能性があります。

import UIKitclass ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { ...}

型が準拠する各プロトコルの拡張機能を作成することで、コードを整理しておくことができます。

import UIKitclass ViewController: UIViewController { ...}extension ViewController: UITableViewDataSource { ...}extension ViewController: UITableViewDelegate { ...}

Xcodeのソースエディタの上部にあるジャンプバーを使用する習慣にすると、ソースファイルのナビゲートも簡単になります。

Xcodeのソースエディタの上部にあるジャンプバーを使用する習慣にすると、ソースファイルのナビゲートも簡単になります。

初期化子の保存

私はChris Eidhofから次のトリックを学びました。 この例では、まず構造体Personを定義する必要があります。 この構造体は、String型、first型、およびlast型の2つの定数プロパティを定義します。

struct Person { // MARK: - Properties let first: String let last: String}

Swiftは、Person構造体のインスタンスをインスタンス化するために使用できる初期化子init(first:last:)を寛大に作成します。 これは新しいものではありません。

let john = Person(first: "John", last: "Doe")

残念ながら、構造体の定義でカスタム初期化子を定義すると、初期化子は使用できなくなりました。

struct Person { // MARK: - Properties let first: String let last: String // MARK: - Initialization init(dictionary: ) { self.first = dictionary ?? "John" self.last = dictionary ?? "Doe" }}

構造体定義でカスタム初期化子を定義すると、初期化子は使用できなくなります。

幸いにも、我々はこの問題を解決するための簡単な回避策を持っています。 カスタム初期化子を定義するPerson構造体の拡張を作成します。

struct Person { // MARK: - Properties let first: String let last: String}extension Person { // MARK: - Initialization init(dictionary: ) { self.first = dictionary ?? "John" self.last = dictionary ?? "Doe" }}

拡張機能は、問題を解決します。

コード分離

前の例をさらに一歩進めることができます。 数年前、Natasha Murashevは拡張機能を使用して状態を動作から分離する技術を概説しました。 この手法を前の例に適用すると、次のようなものになります。

struct Person { // MARK: - Properties let first: String let last: String}extension Person { // MARK: - Initialization init(dictionary: ) { self.first = dictionary ?? "John" self.last = dictionary ?? "Doe" } // MARK: - Public API var asDictionary: { return }}

型定義は、格納されているプロパティのみを定義します。 型の動作、つまりメソッドと計算されたプロパティの拡張が作成されます。 その結果、状態(保存されたプロパティ)と動作(メソッドと計算されたプロパティ)が明確に分離されます。

プライベートビヘイビアのための第二のプライベート拡張を作成することで、これをさらに一歩進めることができます。

struct Person { // MARK: - Properties let first: String let last: String}extension Person { ...}private extension Person { ...}

コードの分離と組織化は、拡張機能を使用して非常に簡単に実行できます。 私はそれをすべての時間を使用します。 Objective-Cのヘッダーファイルがない場合、これは良い選択肢です。

ネストされた型

Swiftプログラミング言語では、拡張機能を使用してネストされた型を定義して使用することもできると述べています。 しかし、私はこの機能が過小評価されていると感じています。 たとえば、定数を定義するために、すべてのSwiftプロジェクトで使用します。

数ヶ月前、ビットマスクを使用したカスタムコントロールの構築に関するチュートリアルを公開しました。 このチュートリアルでは、ビットマスクの生の値をuser defaultsデータベースに格納します。

// MARK: - [email protected] func scheduleDidChange(_ sender: SchedulePicker) { // Helpers let userDefaults = UserDefaults.standard // Store Value let scheduleRawValue = sender.schedule.rawValue userDefaults.set(scheduleRawValue, forKey: UserDefaults.Keys.schedule)}

文字列リテラルを使用する代わりに、定数を使用します。 ケースのない列挙型Keysを定義するUserDefaultsクラスの拡張機能を作成します。 列挙型は、Stringschedule型の静的定数プロパティを1つ定義します。

extension UserDefaults { enum Keys { static let schedule = "schedule" }}

あなたが私に尋ねると、結果はかなりいいです。 定数をグループ化することができるだけでなく、コードベース全体に散在するリテラルを避け、定数の名前空間も指定できます。 言い換えれば、定数は覚えやすく、意味があります。

UserDefaults.Keys.schedule

Swift3のリリースに伴い、Appleはいくつかのフレームワークで同様の手法を採用しました。

Notification.Name.UIApplicationWillTerminate

次は何ですか

拡張機能はSwiftでは非常に強力であり、このチュートリアルで示したテクニックは、可能なことのほんの一例です。

あなたの無料コピーをダウンロード
不足しているマニュアル
Swift開発のための

私が始めたときに私が持っていたと思っていたガイド

Swift開発について学ぶ20,000人以上の開発者に参加

無料コピーをダウンロード

コメントを残す

メールアドレスが公開されることはありません。