他のプログラミング言語とは異なり、Swiftでは、カスタム構造体とクラス用にインターフェースとインプリメンテーションのための個別のファイルを作成する必要はありません。Swiftでは、一つのファイルで構造体またはクラスを定義すると、そのクラスまたは構造体への外部インターフェイスが他のコードで自動的に使用できるようになります。
注意
クラスのインスタンスは、伝統的にオブジェクトとして知られています。しかし、Swiftの構造体とクラスは、他の言語に比べてはるかに近い機能を持ちます。この章では、構造体とクラスのインスタンスに適用でする機能について説明します。以下では、インスタンスは、一般的用語として使用します。
構造体とクラスの比較
Swiftの構造体とクラスには次の多くの共通点があります。
- 値を格納するプロパティを定義する
- 機能を提供するメソッドを定義する
- サブスクリプト文法を使用して値へのアクセスを提供するサブスクリプトを定義する
- 初期化を定義して初期状態を設定する
- デフォルトの実装を超えて機能を拡張するために拡張される
- プロトコルに準拠し、特定の種類の標準機能を提供する
クラスには、構造体にはない追加機能があります。
- 継承により、あるクラスが別のクラスの特性を継承できるようになります。
- 型キャストを使用すると、実行時にクラスインスタンスの型を確認およびインタープリットできます。
- デイニシャライザを使用すると、クラスのインスタンスが、割り当てたリソースを解放できます。
- 参照カウントは、クラスインスタンスへの複数の参照を可能にします。
クラスがサポートする追加機能には、複雑さが増すという代償があります。一般的なガイドラインとして、推論しやすい構造体を優先し、必要に応じてクラスを使用します。実際、あなたが定義するカスタムデータ型のほとんどは、構造体および列挙型になるでしょう。
定義構文
struct SomeStructure { // 構造体定義 } class SomeClass { // クラス定義 } // 例 struct Resolution { var width = 0 // プロパティ var height = 0 // プロパティ } class VideoMode { var resolution = Resolution() // プロパティ var interlaced = false // プロパティ var frameRate = 0.0 // プロパティ var name: String? // プロパティ }
注意
構造体またはクラス名は、UpperCamelCase を使用します。プロパティ名とメソッド名は、lowerCamelCaseを使用して、型名と区別します。
構造体とクラスのインスタンス
Resolution
構造体の定義とVideoMode
クラス定義は、形だけを定義します。それら自体は、特定の解像度またはビデオモードを記述していません。そのためには、構造体またはクラスのインスタンスを作成する必要があります。
// インスタンスの作成 let someResolution = Resolution() let someVideoMode = VideoMode()
プロパティへのアクセス
ドット構文を使用してインスタンスのプロパティにアクセスできます。
// プロパティへのアクセス例 print(someResolution.width) // サブプロパティへのアクセス例 someVideoMode.resolution.width = 1280 print(someVideoMode.resolution.width)
構造型のメンバーのイニシャライザー
すべての構造体は、自動的に生成されるメンバーのイニシャライザーができます。
let vga = Resolution(width: 640, height: 480)
構造体とは異なり、クラスインスタンスはデフォルトのメンバーのイニシャライザーはありません。
構造体と enum は値型
Swiftのすべての基本型(整数、浮動小数点数、ブール値、文字列、配列、および辞書)は値型であり、構造体として実装されています。
すべての構造体と enum は、値型です。つまり、構造体と enum のインスタンス、およびプロパティは、コード内で渡されるときに常にコピーされます。
注意
配列、辞書、文字列などの標準ライブラリによって定義されたコレクションは、値型ですが、コピーのコストを最適化されており、すぐにコピーを作成せずに、元のインスタンスとコピーの間で要素のメモリを共有します。コレクションのコピーの1つが変更された場合、要素は変更の直前にコピーされます。このため、コピーがすぐに行われたかのように見えます。
let hd = Resolution(width: 1920, height: 1080) var cinema = hd cinema.width = 2048
この時、プロパティはコピーされます。
クラスは参照型です
値型とは異なり、参照型は、変数または定数に割り当てられたとき、または関数に渡されたときにコピーされません。コピーではなく、同じ既存のインスタンスへの参照が使用されます。
let tenEighty = VideoMode() tenEighty.resolution = hd tenEighty.interlaced = true tenEighty.name = "1080i" tenEighty.frameRate = 25.0 let alsoTenEighty = tenEighty alsoTenEighty.frameRate = 30.0
クラスは参照型であり、この場合、下の図に示すように、同じ単一インスタンスの2つの異なる名前にすぎません。
この例は、参照型が推論するのがいかに難しいかについても示しています。プログラムのコードに遠く離れていた場合、ビデオモードが変更されていることを見つけることは困難である可能性があります。値の型の方が簡単に推論できます。
アイデンティティーオペレーター
2つの定数または変数がクラスのまったく同じインスタンスを参照しているかどうかを確認する 2つの アイデンティティオペレーターが用意されています。
===
同じ!==
同一ではない
if tenEighty === alsoTenEighty { print("tenEightyとalsoTenEightyは、同じインスタンス") }
独自のカスタム構造体とクラスを定義する場合、2つのインスタンスが等しいと見なされるものを決定するのはユーザーの責任です。==
and !=
演算子の独自の実装を定義するプロセスについては、「等価演算子」で説明しています。
ポインタ
C、C ++、またはObjective-Cの経験がある場合は、これらの言語がポインターを使用してメモリ内のアドレスを参照していることを知っているかもしれません。ある参照型のインスタンスを参照するSwift定数または変数は、Cのポインターに似ていますが、メモリ内のアドレスへの直接のポインターではなく、アスタリスク(*
)を記述する必要はありません。代わりに、これらの参照はSwiftの他の定数または変数と同様に定義されます。標準ライブラリは、ポインタと直接対話する必要がある場合に使用できるポインタとバッファタイプを提供します。「手動メモリ管理」を参照してください。