ストアドプロパティは、特定のクラスや構造体のインスタンスの一部として、シンプルな形式で保存される定数または変数のことです。ストアドプロパティは、(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
を記述して、遅延ストアドプロパティにします。
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" と出力
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.