Swiftのデータ型(Type)は、「値型」(Value Type)と「参照型」(Reference Type)の2種類に大別されます。Swiftではオブジェクトを生成するひな形として「クラス」と「構造体」(および「列挙型」など)がありますが、クラスは参照型、その他の型が値型です。

■■ 値型

値型の値の場合には、インスタンスを別の変数に代入した場合に、値がコピーされます。たとえば、Swiftでは文字列(String型)は構造体として定義されています。したがって値型です。
次のようにすると、str1の文字列がstr2にコピーされます。

var str1: String = "こんにちは"
var str2: String = str1


この状態では、str1とstr2はどちらも別の実体を参照しています。

◎図 value1

value1

したがって、次のようにstr1に、文字列を加えるappend(_:)メソッドを実行すると、str1のみが変更されます。

str1.append("Swift")
print("str1: \(str1)") // => str1: こんにちはSwift
print("str2: \(str2)") // => str2: こんにちは

 

同様に、オリジナルの構造体の場合も同様です。次のようなインスタンス変数numを持つMyStrut構造体の例で説明しましょう。

struct MyStruct{
    var num: Int = 0
}

次のようにMyStructのインスタンスを生成しms1に代入し、それを別の変数ms2に代入したとしましょう。

var ms1: MyStruct = MyStruct()
var ms2: MyStruct = ms1

 

この場合、ms1とms2は独自の実体を参照しています。したがって、ms1のnumの値を変更してもms2には反映されません。

print("ms1: \(ms1.num)") // => 0
print("ms2: \(ms2.num)") // => 0
ms1.num = 10; // ms1のnumを10に変更
print("ms1: \(ms1.num)") // => 10
print("ms2: \(ms2.num)") // => 0


■■ 参照型

参照型の値の場合、インスタンスを別の変数に代入した場合に、どちらも同じ実体を参照するようになります。次のような、インスタンス変数numを持つMyClassクラスの例で説明しましょう。これは前述のMyStruct構造体をクラスに変更したものです。

class MyClass{
    var num: Int = 0
}

 

次のようにMyClassのインスタンスを生成し変数mc1に代入し、それを別の変数mc2に代入したとしましょう。

var mc1: MyClass = MyClass()
var mc2: MyClass = mc1


この場合、mc1とmc2は同じ実体を参照しています。

◎図 value2

value2

print("mc1: \(mc1.num)") // => 0
print("mc2: \(mc2.num)") // => 0

 

したがって、mc1のインスタンス変数numを変更するとmc2にも反映されます。

mc1.num = 10; // mc1のnumを10に変更
print("mc1: \(mc1.num)") // => 10
print("mc2: \(mc2.num)") // => 10

 

■■ varとletの相違

Swiftでは、変数をvarで宣言すると後から変更可能、letで宣言すると変更不可になります。この場合も値型と参照型では動作が異なります。
値型の場合には、letで宣言するとインスタンス変数を変更することはできません。次に、MyStruct構造体の変数ms3をletで宣言しインスタンス変数numの値を変更するとエラーになる例を示します。

struct MyStruct{
    var num: Int = 0
}
let ms3 = MyStruct() // <= letで宣言
ms3.num = 9 // <= エラー


また、letで宣言された変数に別のインスタンスを再代入することもできません。

let ms3 = MyStruct() // <= letで宣言
ms3 = MyStruct() // <= エラー

クラスのような参照型の場合には、変数をletで宣言してもインスタンス変数を変更できます。ただし、letで宣言した変数に別のインスタンスを再代入することはできません。

let mc3 = MyClass()
mc3.num = 3 // <= OK
mc3 = MyClass() // <= エラー

 

■■ 「===」演算子

参照型の値の場合、「===」演算子(および「!==」)で2つの変数が同じ実体を参照しているかどうかを確認できます。

class MyClass{
    var num: Int = 0
}

var mc1: MyClass = MyClass()
var mc2: MyClass = mc1
var mc3: MyClass = MyClass()

print(mc1 === mc2) // => true
print(mc1 === mc3) // => false