【プログラミング初心者】Swift基礎~値型・参照型~

##はじめに
クラスと構造体の違いについて説明します。
[Swift基礎~構造体・クラス~](https://qiita.com/euJcIKfcqwnzDui/items/f6e41f6b8f068c620ac6)という記事で使った構造体やクラスを使って説明していくのでまずそちらを参照して頂ければと思います。

今回の内容はC言語でいうところのポインタ、動的メモリ確保です。
今対象にしているSwiftなどの言語では意識することが少ない内容となります。
言い換えるとそこまで理解していなくてもSwiftならある程度実装できるので難しければ保留にしておいてもいいかもしれません。

## メモリについて
前提知識として少しメモリの話をします。

まずメモリを扱うには**確保**と**開放**という操作が必要になります。
そのままの意味ですが確保すると「今からこの領域を使います」というようにそのデータが対象のメモリを専有します。開放はその専有をやめることです。使用されているメモリは他から急に書き換えられると困るので開放されるまでは他からは使えません。

よく一口にメモリと言っていますが、OSはこのメモリを**スタック領域**と**ヒープ領域**に分けて管理しています。
スタック領域とヒープ領域は、どちらも一時的に確保されるメモリ領域ですがそれぞれ管理方法が異なります。

- スタック領域
    - メモリがA→B→Cの順で確保された場合、C→B→Aの順で解放される。メモリをいわゆるスタックで管理している。<br>処理ブロック(`{}`で囲まれたブロック)を抜けると解放されるという特長がある。<br>ヒープよりも割り当てられている領域が小さい。
- ヒープ領域
    - 確保されたメモリは明示的に解放しないとずっと留まり続ける。そのため気をつけていなければメモリリークを引き起こしクラッシュの原因になる。<br>自由なサイズのメモリを確保できるというのが特長。

変数の参照先は全てスタックに格納された値です。
ここまでは前提知識として覚えておいてください。

## クラスと構造体の違い
クラスと構造体は若干プログラムの定義の仕方が異なる部分もありますが基本的には同じように扱えます。
ですが根本的に異なる部分があります。
それは実体化したときのメモリの取られ方です。

構造体、クラスはそれぞれ**値型**と**参照型**と呼ばれます。

### 値型
まず値型と呼ばれる構造体について。
[Swift基礎~構造体・クラス~](https://qiita.com/euJcIKfcqwnzDui/items/f6e41f6b8f068c620ac6)で作った`Company`構造体を例にして説明していきます。
[以前](https://qiita.com/euJcIKfcqwnzDui/items/5d4c674a975c90a3db3f#%E3%83%A1%E3%83%A2%E3%83%AA%E3%82%A2%E3%83%89%E3%83%AC%E3%82%B9)変数のメモリの取られ方について説明しました。
このときはIntを題材にしましたが、定義を見ればわかりますが実はIntも構造体です。
なのでメモリの長さは異なりますが、以前説明したメモリの取られ方と基本的には同じです。
詳細な取られ方はわかりませんが構造体は以下のようなイメージでメモリが確保されます。
<img width="932" alt="構造体.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326173/2dff4b8b-5ee0-8b1e-7f3c-698f93a48eb5.png">

値型、つまり構造体の場合値の全てがスタック領域に確保されます。
例えば以下のような宣言をした場合

```swift
var company: Company = Company(name: "株式会社山田商事",
                               president: "山田太郎",
                               earnings: 1000000,
                               departments: [])
```
以下のようなイメージになります。
<img width="1192" alt="値型１.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326173/ca4a2044-1794-63eb-5115-619eadbba145.png">
これは特に疑問なくイメージできるかと思います。

今度は以下の場合を見てみましょう。

```swift
var company: Company = Company(name: "株式会社山田商事",
                               president: "山田太郎",
                               earnings: 1000000,
                               departments: [])
var tmpCompany = company
```
この場合はどうでしょう？
これもスタックに確保されるのですが、新しく確保された領域にコピーされた値が格納されます。
<img width="1228" alt="値型２.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326173/33aedc98-45dc-7129-7b4d-d147e77f436e.png">
値型の場合変数には値そのものが入っています。
そのため新しく`tmpCompany`を宣言した場合も`company`の**値**が代入されます。

確認してみましょう。
以下のコードで出力を見てみます。

```swift
var company: Company = Company(name: "株式会社山田商事",
                               president: "山田太郎",
                               earnings: 1000000,
                               departments: [developDepartment, salesDepartment])
var tmpCompany = company
company.name = "nameを更新"
print("company: " + company.name)
print("tmpCompany: " + tmpCompany.name)
```
```:出力
company: nameを更新
tmpCompany: 株式会社山田商事
```
`tmpCompany.name`が変更されていないことがわかりますね。
つまり別の領域として確保されたということです。

値型の場合スタックに値がコピーされ続けるのでデータ量の多い構造体の場合メモリを大きく食いつぶす可能性があります。
スタック領域はヒープ領域に比べて容量が小さいのですぐ使い切ってしまいます。
この場合スタックを使い切ってしまったエラーを**スタックオーバーフロー**といいます。
プログラムは当然クラッシュします。

### 参照型
一方参照型と呼ばれるクラスは**ヒープ領域に確保**されます。
変数は全てスタック領域に確保された値と先述しました。
では参照型の変数にはどんな値が確保されるのでしょうか？

答えはヒープに確保された領域の先頭アドレスです。

[Swift基礎~構造体・クラス~](https://qiita.com/euJcIKfcqwnzDui/items/f6e41f6b8f068c620ac6)作った`Human`クラスを例にして説明します。

以下のコードでオブジェクトを生成し変数に格納します。

```swift
var human = Human(name: "山田太郎", age: 25)
```
クラスの場合ヒープ領域に確保されると言いましたが、その確保のされ方は値型がスタックに確保される時と同じです。
違うのは`Human(name: "山田太郎", age: 25)`が返す値が生成された領域の先頭アドレスということだけです。
つまり`human`にはオブジェクトのアドレスが格納されています。
図で表すと以下の様になります。
<img width="1097" alt="参照型１.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326173/f3420517-5cce-29e9-3d13-f5367e234e5d.png">
このように値そのものではなく、オブジェクトへの**参照**を変数に格納することから参照型と呼ばれています。
(C言語ではポインタ型と言われ、この場合Humanポインタ型と呼びます)

では以下のように`human`を新しい変数に格納した場合はどのようになるでしょう？

```swift
var human = Human(name: "山田太郎", age: 25)
var tmpHuman = human
```
何度か言っているように変数はスタックに確保されます。
そして値型どうように変数宣言をすると新しくスタック領域に値のコピーが作成されます。
つまり以下のようになります。
<img width="1133" alt="参照型２.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326173/8da0654f-f750-2a51-af6b-9224bfbe0b64.png">
このように変数にはアドレスという値がコピーされ、実際指し示すアドレスは同じオブジェクトなので`human`と`tmpHuman`は同じものと見なすことができます。

確認してみましょう。
以下のコードで出力を見てみます。

```swift
var human = Human(name: "山田太郎", age: 25)
var tmpHuman = human
human.name = "nameを更新"
print("human: " + human.name)
print("tmpHuman: " + tmpHuman.name)
```
```:出力
human: nameを更新
tmpHuman: nameを更新
```
`human`を更新すると`tmpHuman`も一緒に更新されました。
つまり同一オブジェクトを参照していることがわかりますね。

このように参照型の場合は変数に代入するときアドレスのみがコピーされます。
これを浅いコピーという意味で**シャローコピー(shallow copy)**と言います。
反対に値型の場合内部のメンバ変数全てが別領域に同じ値としてコピーされるので、深いコピー**ディープコピー(deep copy)**と呼びます。

自分がやっている実装はshallow copyなのかdeep copyなのかをしっかり意識しておかなければ、いつの間にか書き換わっていたり書き換えたと思っていたのに書き換わっていなかったということになりかねません。
気をつけて実装してください。

## ガベージコレクション
少し話が変わります。
冒頭のヒープ領域の説明で以下のように説明しました。
> 確保されたメモリは明示的に解放しないとずっと留まり続ける。

C言語の場合不要になった時`free(変数)`というように明示的に開放処理を行います。

Swiftではどうやって解放すればいいのでしょうか？
結論から言うとSwiftでは解放する必要がありません。
というよりはシステム的に自動的に解放されるようになっています。

この自動で解放してくれる仕組みのことを**ガベージコレクション(garbage collection:GC)**と呼びます。

GCではヒープで確保した領域に対して**参照カウンタ**というものを持ちます。
そのままの意味で何個の変数から参照されているのかカウントするものです。

例えば先程使った例でいうと

```swift
var human = Human(name: "山田太郎", age: 25)
var tmpHuman = human
```
というように２つの変数から参照しました。
この段階で参照カウンタは２となります。

ここから

```swift
tmpHuman = nil
```
とします。
`nil`はどこのアドレスも指していないという意味です。
そうすると参照カウンタが-1され１となります。
この参照カウンタが０になったタイミングでオブジェクトは解放されます。

これがGCという機能です。

また`tmpHuman = nil`のようにしなくても問題ありません。
変数は全てスタック、スタックは処理ブロックを抜けると解放されると説明しました。

つまり`{}`を抜けると変数は解放され、参照カウントが自動的に-1されるというわけです。
そのためSwiftではあまり解放を意識する機会はありません。

ITの基本知識として押さえる程度でいいかと思います。

## 最後に
今回クラスと構造体の違いについて説明しました。
このあたりは知らないと思わぬバグを引き起こす原因になりうるので知っていてほしい内容ではあります。
配列などは参照型なのか値型なのか言語によって分かれるところで、新しい言語を触るとよくバグる部分だったりします。

ですが意外とプログラマの中にもあまりしっかりと理解せずコーディングしている人も多いように感じます。
最近の言語は便利になったため知らなくてもコーディングできてしまうためかと思います。
なので最初のうちはわからなくても問題ないかと思います。

ですがいずれ身につけてもらえるとプログラムを深く理解できるようになるかと思います。

今回の内容は以上です。
本記事とは別でプログラミング未経験からiOSアプリ開発が行えるようになることを目的とした記事を連載しています。
連載は以下にまとめていますのでそちらも是非もご覧ください。
http://naoyalog.com/