【swift】イラストで分かる！classとstructの違いについて【初心者向け】

## 概要
👨‍🏫「ここってstructで書いてるけど、意味とかあって書いた？」
🙍‍♀️「！」
🙍‍♀️「定数を並べただけのものだったので、そういうのはstructの方がいいかなって..」
👨‍🏫「ほーん」
🙍‍♀️「正直言うと意味なくstructにしました」
👨‍🏫「ほーん」

ということがあったので、
改めてそれぞれどういう違いがあるのかを改めて整理してみました٩( 'ω' )و

## それぞれの特徴
先に、それぞれについての特徴をパッと簡単に確認。
イメージは[@loveeさんの記事]
(https://qiita.com/lovee/items/0bf5e663dd74983cc0d3)を参考にしています。
<img src="https://qiita-image-store.s3.amazonaws.com/0/146629/ea9c8790-b0cb-f1c4-75f6-f145db899c66.png" width="500">

ポイントとなるのは参照型か値型か、ってところですね🤔
また、コードを書いてみると、

```swift:struct
struct test {
    let cat: String
    let dog: String
}
/// -> 怒られない
```

```swift:class
class test {
    let cat: String
    let dog: String
}
/// -> 💥怒られる：　Class 'test' has no initializers
```

クラスの方は初期化して！と怒られます。


## 実装して違いを見てみよう

```swift
class Cat {
    var like: String = "魚"
}
struct Dog {
    var like: String = "肉"
}
```
クラスで作られた魚好きの🐱とストラクトで作られた肉好きの🐶。

```swift
let tama: Cat = Cat()
let pochi: Dog = Dog()

func initWithData(_ data: Cat) {
 var data = data
 data.like = "マタタビ"
}

func initWithData2(_ data: Dog) {
 var data = data
 data.like = "マタタビ"
}

initWithData(tama)
initWithData2(pochi)
```
それぞれを連れてきてマタタビをあげてみると、

```swift
print(tama.like) // →"マタタビ"
print(pochi.like) // →"肉"
```
という結果に。🐱は好物が魚からマタタビに書き換わりました。

この実行結果から見ても、
class🐱は参照渡しなので、
`var data = data`で、cat()そのものが渡されており、
`var tama: cat = cat()`自体が書き換わっているのに対して、
struct🐶は値渡しなので、
`var data = data`で、cat()のコピーが作られ、
`var pochi: dog = dog()`自体が書き換わることはありません٩( 'ω' )و

ご存知の通り？initで初期値を入れることもできます。

```swift
class Cat {
    var like: String
    init(like: String) {
        self.like = like
    }
}
struct Dog {
    var like: String
    init(like: String) {
        self.like = like
    }
}
let tama: cat = Cat(like: "魚")
let pochi: dog = Dog(like: "肉")
```
ただし、その場合は、

```swift
let tama: cat = Cat(like: "魚")
tama.like = "肉" // →"肉"
let pochi: dog = Dog(like: "肉")
pochi.like = "魚" // ERROR
```

となります。struct🐶は好き嫌いが激しいです。
これはstructは値渡しなので、例えて言うと、
<img src="https://qiita-image-store.s3.amazonaws.com/0/146629/841e6ad2-3c7f-edde-1220-2f72cb3fe0e7.png" width="500">

実体（＝参照型class🐱）に直接手を加えることはできるけど、
写真（＝値型struct🐶）に直接手を加えることはできない（写真の加工とかは置いておいて..）
といったイメージで大丈夫だと思います٩( 'ω' )و

## 公式ドキュメント
Appleの[公式ドキュメント](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ClassesAndStructures.html#//apple_ref/doc/uid/TP40014097-CH13-ID82)にstructは以下の場面で使い、それ以外はclassを使用するのが良いという内容が書かれていました。（意訳）

* structの目的は比較的単純なデータ値をカプセル化すること
* インスタンスを代入または受け渡しするときは、カプセル化された値が参照ではなくコピーされる
* structに格納されているプロパティはすべて値型であり、参照ではなくコピーされる
* structは、他の既存の型からプロパティや動作を継承する必要はありません。


## ついでに
ちなみにそもそも発端となったコードは以下のようなものでした。

```swift
/// カラーの拡張（各所で、'let xxx = UIColor.mainGreenColor()'などと呼ぶ）
extension UIColor {
	// UIColorへの変換
	private func hexColor(_ str: String) -> UIColor {
		// (略)ここでカラーコード→UIColorに変える
		return UIColor(red: x, green: x, blue: x, alpha: 1.0)
	}
	// メインカラー		
	@objc static func mainGreenColor() -> UIColor {
		return self.hexColor(ColorCode.mainGreenColor)
	}
	// バッチカラー
	@objc static func badgeColor() -> UIColor {			
		return self.hexColor(ColorCode.badgeColor)
	}				
	// カラーコード
	struct ColorCode { // ←⭐️ここ	
		static let mainGreenColor: String = "#219E62"
		static let badgeColor: String = "#FF3300"
	}
}
```

色々調べてみた結果としては、
「staticな変数だけをまとめたものだから、メモリを無駄に増やさないようにっていう観点でも`class`を使うのがベターだな」
っていうのが理解できました😇
<img src="https://qiita-image-store.s3.amazonaws.com/0/146629/3eb64246-ed5d-cdc4-6d41-8d67ce06cfa6.png" width="500">



## 最後に
ちゃんと調べる前は、チームによってとか人によって結構好みの問題もあるんじゃないかとかって思っていたのですが、
ちゃんと意味を持った使い分けも出来るんだな、と改めて理解できました٩( 'ω' )و

## 最後の最後
delegate=selfとか諸々すごく端折っているのですが、
以下のコードのような`CatViewData`というデータを常に更新して保持するクラスを作り持ち回すという構成で書いたときに、
あまり考えずに`struct`を使った結果、データが全く更新(保持)されずで小一時間悩んで「んあぁぁああああ😭！！！！！」ってなったことがあったので、
結構動作に影響する場面があったりもするのでそいう意味でもちゃんと考えて使っていきたいところです。

```swift

/// データ保持用クラス
// ↓structにすると、データを書き換えても値型でコピーされるだけなので、呼び直すタイミングで消えてしまう
class CatViewData {
    var name: String
    init(name: String) {
        self. name = name
    }
}

/// VC&Table用クラス
class TableViewDataSource: UIViewController, UITableViewDelegate, UITableViewDataSource {
    var viewData: CatViewData

    // ここでテーブルを更新
    func reloadTable(viewData: CatViewData) {
        tableView.reloadData()
        self.initWithData(viewData: viewData)
    }

    // ここでデータを更新
    func initWithData(viewData: CatViewData) {
        self.viewData = viewData
    }

    // ~~略~~
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "CatCell") as! CatCell
	cell.setSettingCell(viewData: viewData)
	return cell
    }

       func reloadTable(viewData: CatViewData) {

      }
}

/// 表示用のセルクラス
protocol delegate {
      func reloadTable(viewData: CatViewData)
}
class CatCell: UITableViewCell {
     var viewData: CatViewData
     func setSettingCell(viewData: viewData) {
          self.viewData = viewData
    }
    @IBAction func buttonTapped(sender:AnyObject) {
        self.viewData = "(textViewから入力したデータ)"
        delegate.reloadTable(viewData: self.viewData)
    }
}
```

簡単ですが以上です。
誤っている箇所等ありましたらコメントいただけると幸いです。