ストアドプロパティは、特定のクラスや構造体のインスタンスの一部として、シンプルな形式で保存される定数または変数のことです。ストアドプロパティは、(var キーワードで)変数のストアドプロパティ、または(let キーワードで)定数のストアドプロパティのどちらにでもすることができます。

Default Property Values で説明されているように、定義の一部としてストアドプロパティにデフォルト値を与えることができます。初期化の間にストアドプロパティの初期値を設定あるいは変更することもできます。これは、Assigning Constant Properties During Initialization で説明されているように、定数のストアドプロパティの場合にも当てはまります。

次の例では、生成後に範囲の長さを変更できない整数値の範囲を持つ、構造体 FixedLengthRange を定義しています。

struct FixedLengthRange {
    var firstValue: Int
    let length: Int
}
var rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3)
// 範囲の整数値は 0, 1, 2
rangeOfThreeItems.firstValue = 6
// 範囲の整数値は 6, 7, 8

fixedLengthRange のインスタンスには、変数のストアドプロパティ firstValue と、定数のストアドプロパティ length があります。上の例では、length は新しい範囲が生成される時に初期化されますが、定数のプロパティであるため、それ以降は変更できません。

定数の構造体インスタンスのストアドプロパティ

構造体のインスタンスを生成して定数に代入した場合、インスタンスのプロパティが変数のプロパティとして宣言されていたとしても、変更することはできません。

let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4)
// この範囲の整数値は 0, 1, 2, 3
rangeOfFourItems.firstValue = 6
// firstValue は変数のプロパティだけれども、エラーとなる

rangeOfFourItems が定数として(let キーワードで)宣言されているため、firstValue は変数のプロパティですが、firstValue プロパティを変更することはできません。

この振る舞いは、構造体が値型であるためです。値型のインスタンスが定数としてマークされているとき、そのプロパティのすべてがそうなります。

参照型であるクラスでは同じようにはなりません。参照型のインスタンスを定数に代入した場合は、そのインスタンスの変数のプロパティを変更することができます。

遅延ストアドプロパティ

遅延ストアドプロパティは、初めて利用されるまで初期値が算出されないプロパティです。宣言の前に lazy を記述して、遅延ストアドプロパティにします。

NOTE
インスタンスが初期化を完了するまで初期値が取り出されることがないため、遅延プロパティを常に(var キーワードで)変数として宣言する必要があります。定数のプロパティは、初期化を完了する前に常に値を持つ必要があり、遅延として宣言することはできません。

遅延プロパティは、インスタンスの初期化が完了するまで値がわからない外部の要因に、プロパティの初期値が依存しているときに役立ちます。プロパティの初期値が複雑か計算コストが高いセットアップを必要とし、そのセットアップが必要とならないか、必要となるまで実行すべきでないときにも、遅延プロパティは役立ちます。

次の例では、複雑なクラスの不必要な初期化を避けるために遅延ストアドプロパティを使用しています。この例では、2 つのクラス DataImporter と DataManager を、どちらも完全ではないですが定義しています。

class DataImporter {
    /*
     DataImporter は外部ファイルからデータをインポートするクラス。
     クラスは初期化にささいでない時間を要すると想定される。
     */
    var fileName = "data.txt"
    // DataImporter クラスはデータをインポートする機能を持つ
}

class DataManager {
    lazy var importer = DataImporter()
    var data = [String]()
    // DataManager クラスはデータ管理機能を持つ
}

let manager = DataManager()
manager.data.append("Some data")
manager.data.append("Some more data")
// importer プロパティの DataImporter インスタンスはまだ生成されていない

DataManager クラスには、String 値の空配列で初期化されているストアドプロパティの data があります。機能の残りは示されていませんが、DataManager クラスの目的は、この String データ配列へのアクセスを管理、提供することです。

DataManager クラスの機能性の一部は、ファイルからデータをインポートする能力です。この機能性は、初期化にささいでない時間を要すると想定される DataImporter クラスによるものです。これは、DataImporter インスタンスが初期化されるときに、DataImporter インスタンスがファイルを開いて、そのコンテンツをメモリに読み込む必要があるためです。

DataManager インスタンスは、ファイルからデータをインポートすることなく、データを管理することが可能です。そのため、DataManager が生成されるときに、DataImporter インスタンスを生成する必要はありません。そうではなく、DataImporter インスタンスが初めて利用されるときに生成することが理にかなっています。

importer プロパティに lazy が付けられているため、fileName プロパティを問い合わせるときのように、importer プロパティに初めてアクセスしたときに DataImporter インスタンスは生成されます。

print(manager.importer.fileName)
// importer プロパティの DataImporter インスタンスは生成されている
// "data.txt" と出力
NOTE
lazy と付けられたプロパティが複数のスレッドから同時にアクセスされ、まだ初期化されていない場合、そのプロパティが一度だけ初期化されるという保証はありません。

ストアドプロパティとインスタンス変数

Objective-C の経験がある場合、値を保管してクラスインスタンスの一部として参照するために 2 つの方法があることをご存知だと思います。プロパティに加えて、プロパティで保持された値のバックアップとしてインスタンス変数を利用することができます。

Swift では、これらのコンセプトを 1 つのプロパティ宣言に統合しています。Swift のプロパティには、相当するインスタンス変数が無く、プロパティのバックアップは直接アクセスされません。このアプローチが、異なるコンテキストで値がどのようにアクセスされるかについての混乱を避け、プロパティの宣言を簡略化しています。プロパティについて、名前や型、メモリ管理の特徴を含むすべての情報は、型の定義の一部として一箇所で定義されます。


Portions of this page are translations based on work created and shared by Apple and used according to terms described in the Creative Commons Attribution 4.0 International License.