SwiftにおけるClassとStructの使い分け

Swiftでは型を定義する場合、次のように _Value Types_ が好まれる傾向にあります。

- Swift standard library の多くの型が _Value Types_ で実装されている
 - `Swift 2.0 - struct: 87 enum: 8 class: 4`
- _**Prefer structs over classes** by [Github Swift Style Guide](https://github.com/github/swift-style-guide)_

このエントリでは 「_Referece Types_ と _Value Types_ の違い」、「それぞれの型の使い分けについての私の考え」をまとめてみました。

## _Reference Types_ と _Value Types_ の違い

### `=` の挙動
- `Reference Types`
 - インスタンスへの参照ができる
 - インスタンス自体はコピーされない
- `Value Types`
 - インスタンスがコピーされる

#### Reference Type

```
class Point {
    var x: Float = 0.0
    var y: Float = 0.0
}
let p1 = Point()
let p2 = p1
p2.x = 5.0

p1.x // x: 5.0, y: 0.0
p2.x // x: 5.0, y: 0.0
```

- `p1`, `p2` には 同じ `Point` インスタンスの参照が保持される
- 結果、`p2.x`への変更が `p1.x` の値にも反映される

#### Value Type
```
struct Point {
    var x: Float = 0.0
    var y: Float = 0.0
}
let p1 = Point()
var p2 = p1
p2.x = 5.0

p1.x // x: 0.0, y: 0.0
p2.x // x: 5.0, y: 0.0
```

- `p1`, `p2` は別々の `Point` インスタンス
- 結果、`p2.x` への変更は `p1.x` の値に反映されない

### Mutability

- _Reference Types_ と _Value Types_ で `let` の意味するところが異なる。

_**Reference Types**_

- `let`: 参照が不変

```
class Point {
    var x: Float = 0.0
    var y: Float = 0.0
}
let p = Point()
p = Point() // ERROR Cannot assign to value: 'p' is a 'let' constant
```
- インスタンスの値は変更可能

```
p.x = 5.0
```

_**Value Types**_

- `let`: インスタンス自体が不変。プロパティの値も変更不可。(プロパティが`let`, `var`に関係ない)

```
struct Point {
    var x: Float = 0.0
    var y: Float = 0.0
}

let p = Point()
p.x = 10.0 // ERROR Cannot assign to property: 'p' is a 'let' constant
```

_Reference Types_ は、`let`で変数を定数化しても、参照先が変更できないだけで、参照先のインスタンスの値は変更できてしまう。
よって、_Value Types_ の方がMutabilityの管理が容易。
_Reference Types_ にて同様のことを実現しようとすると `NSString` と `NSMutableString` みたいな関係のクラスを自前で実装する必要がある。


## ここまでのまとめ
#### `=` の挙動
- `Value Types`
 - インスタンスが複製される
- `Reference Types`
 - インスタンスへの参照ができる

#### Mutability
- `Value Types`
 - `let` によりインスタンスの値（プロパティ含む）を不変にできる
- `Reference Types`
 - `let` でインスタンスへの参照は不変になるが、インスタンスの値は変更可能


## 使い分け: _Reference Types_ / _Value Types_
通常、型はmutabilityの管理が容易な方が好ましい。
まず _Value Types_ で要件を満たせないかを検討する。

#### `Value Types`
- `=` において、インスタンスが複製され、独立性が維持された方が良い場合

```
let initialPoint = Point(x: 0, y: 0)
var circle = Shape(center: initialPoint)
let square = Shape(center: initialPoint)

// `circle` と `square` は独立したインスタンス
// それぞれが `center` を管理している
circle.center.x = 2 // {x: 2, y: 0}
square.center       // {x: 0, y: 0}
```

#### `Reference Types`
- Cocoaのクラスを使う場合
 - `XXXViewController`, `YYYTableViewCell` など
- インスタンスをMutableにして共有したい場合

 ```
 class Account {
   var balance = 0.0
 }

 class Person {
   let account: Account
   init(_ account: Account) {
     self.account = account
   }
 }

 let account = Account()

 let husband = Person(account)
 let wife = Person(account)

 husband.accout.balance += 1000
 wife.account.balance -= 500

 account.balance // 500
 ```

# まとめ
「_Reference Types_ と _Value Types_ の違い」、「使い分け: _Reference Types_ / _Value Types_」についてまとめてみました。
Swift standard libraryが _Value Types_ を多く用いているのは immutability を担保し易いからでしょう。
このエントリを書く上で色々なブログエントリを読んだのですが、
型を作る場合、まずは`Struct`で実装できないか検討するのがSwift的に良いプラクティスなのかと思うようになりました。

# References
- [Value and Reference Types](https://developer.apple.com/swift/blog/?id=10)
- [When to Use Swift Structs and Classes by Mike Ash ](https://www.mikeash.com/pyblog/friday-qa-2015-07-17-when-to-use-swift-structs-and-classes.html)
- [Reference vs Value Types in Swift: Part 1/2](http://www.raywenderlich.com/112027/reference-value-types-in-swift-part-1)
- [Github Swift Style Guide](https://github.com/github/swift-style-guide)