2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Swift】変数における値型と参照型の違いについて

Last updated at Posted at 2025-03-03

Swiftの値型と参照型の違い

Swiftには「値型(Value Type)」と「参照型(Reference Type)」の2種類のデータ型があり、それぞれ挙動が異なります。
変数を扱う際にこの違いを理解しておくことで、意図しないバグを防ぐことができます。

前提:変数と定数の基本

Swiftでは、データを格納するために「変数(var)」と「定数(let)」を使います。

  • var(変数): 値を変更できる
  • let(定数): 値を変更できない
var number = 10 // 変数なので値を変更できる
number = 20

let constantNumber = 10 // 定数なので値を変更できない
// constantNumber = 20 // これはエラー

この「変更できるかどうか」のルールは、値型と参照型の違いとも関連します。

値型(Value Type)とは

値型は、変数がデータそのものを保持している型です。
値型の変数を他の変数に代入すると、データはコピーされます。

値型に分類されるもの

  • 構造体(Struct)
  • 列挙型(Enum)
  • タプル(Tuple)
  • 標準ライブラリの型(String、Int、Boolなど)

値型の挙動

struct MyStruct {
    var value: Int
}

var a = MyStruct(value: 10)
var b = a // `a`のコピーが作られる

b.value = 20

print(a.value) // 10
print(b.value) // 20

この例では、ba を代入した時点で a のコピーが作成されます。そのため、b を変更しても a には影響しません。

値型のメリット

  • データの独立性が保たれる → ある変数の変更が、他の変数に影響を与えない。
  • スレッドセーフ → マルチスレッド環境でも安全に扱える。

参照型(Reference Type)とは

参照型は、変数がデータのアドレス(メモリ上の位置)を保持している型です。
参照型の変数を他の変数に代入しても、データそのものはコピーされず、同じデータを指す別の参照が作られます。

参照型に分類されるもの

  • クラス(Class)
  • クロージャ(Closure)
  • Objective-Cのオブジェクト(NSString, NSArray など)

参照型の挙動(同じデータを指す)

class MyClass {
    var value: Int
    
    init(value: Int) {
        self.value = value
    }
    
}

var a = MyClass(value: 10)
var b = a // `a`と`b`は同じインスタンスを参照

b.value = 20

print(a.value) // 20
print(b.value) // 20

この例では、ba を代入してもコピーは発生せず、ab は同じメモリアドレスを指します。そのため、b を変更すると a も変更されます。

参照型の注意点

  • データが共有されるため、意図しない変更が起こる可能性がある
  • マルチスレッド環境では同期処理が必要になる場合がある

よくあるバグの例

値型と参照型の誤解によるバグ

struct Counter {
    var count: Int = 0
}

func increment(counter: Counter) {
    var counter = counter
    counter.count += 1
}

var myCounter = Counter()

increment(counter: myCounter)
print(myCounter.count) // 0(変更されていない!)

このバグの原因は、構造体(値型)はコピーされるため、関数内で変更しても元の変数には影響がないことにあります。

修正するには、inout を使って変更を反映させる必要があります。

func increment(counter: inout Counter) {
    counter.count += 1
}

var myCounter = Counter()

increment(counter: &myCounter)
print(myCounter.count) // 1(正しく変更される)

参照型の共有による意図しない変更

class Person {
    var name: String
    
    init(name: String) {
        self.name = name
    }
    
}

var personA = Person(name: "Alice")
var personB = personA

personB.name = "Bob"

print(personA.name) // "Bob"(意図しない変更が発生!)

このバグは、クラス(参照型)はコピーされずに共有される ために起こります。
値の独立性を確保したい場合は、struct を使うべきです。

struct Person {
    var name: String
}

var personA = Person(name: "Alice")
var personB = personA

personB.name = "Bob"

print(personA.name) // "Alice"(変更されない!)

まとめ

値型(Value Type) 参照型(Reference Type)
代入時の動作 コピーが作成される 参照が共有される
データの独立性 保たれる 保たれない
var の影響範囲 その変数のみ すべての参照先に影響
let の制約 プロパティも変更不可 参照は変更不可だが、プロパティ変更は可能

特に「よくあるバグ」の例などは、swiftを経験していれば一度は遭遇する事象だと思います。
その際に「参照先が共有されてるのかな?」などの考えにすぐに至ることができれば、バグの解消もスムーズにできるかと思います。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?