Dependency Injection(依存の注入)とは？

自分が理解したいためにまとめました！間違いがあればぜひご指摘を。

## 1. Dependency Injection(DI)ってなんやねん。

意味を訳すと、Dependency = 依存で、
Injection = 注入、注射するです。つまり、
**「依存していた部分を、外から注入すること」**by　@hshimoさん
つまり、**外からオブジェクトを受け取る**ことです。


## 2. DIが便利なわけ / 使いたい理由

*@hshimo さんから言葉をお借りしてます

柔軟性がない ->  決め打ちなので、柔軟性がなくカスタマイズしにくい
テストしにくい ->  外から動的に動作を変更できないので、テストしづらい

ってイキナリ言われても解らんですよね。そこで例えを使って考えましょう。

## 3. 例で考える

たとえば、ドクターがいて、ナースさんがいて、カルテがあったら、普通はドクターがカルテを書いて、ナースさんに渡してそれを元に患者に対応しますよね？(DI後)

でも、医者がカルテ作成を全部ナースさんに丸投げしたらどうなるでしょうか？　ナースさんはいちいちドクターに患者の状況を聞いてから、カルテを作成しないと行けないです。(DI前)

こうなると、ナースさんの仕事が増えてすごく大変。しかもカルテをドクターが直したい、となったら、ナースさんはまたイチから作成しないといけません。(DI前)

![Screen Shot 2017-07-16 at 12.06.57 AM.png](https://qiita-image-store.s3.amazonaws.com/0/158705/5c9445fd-6260-f1a1-8f6f-fe313919b189.png)



DI前のコード

```
protocol Carte {}
class Doctor{
   func assignNurse() -> Nurse{
      var nurse = Nurse()
      return nurse
   }
}

class Nurse {
    let carte: Carte

    init() {
        carte = Carte()
    }
}
```

```main.swift
doctor.assignNurse()
```

DI後コード

```
class Carte {}
class Doctor{
  func makeCarte() -> Carte{
    var carte = Carte()
    return carte
  }
}

class Nurse {
    let carte: Carte

    init(_ carte: Carte) {
        self.carte = carte
    }
}
```

```main.swift
var carte = doctor.makeCarte()
var nurse = Nurse(carte)

```

DI後コードでは、NurseクラスはCarteをinit(作成してない！)
そして外からcarteオブジェクトを注入にしているので、carteに変更があった場合、Nurseの中身は書き換えなくてもいいので、テストが楽。

DIがを使いたい理由を簡単に説明すると、
**一つのクラスが仕事を持ちすぎているので(クラス依存)、スムーズに事が進むように、仕事を分担する、という感じで。**ナースさんはカルテの中身を知りたいけど、作成方法は一切知らなくてもいい、という感じです。

え、例えとコードが微妙？？ごめんなさい。

## 4. 色々なところで使うDependency Injection


### 1. Viewcontrollerから別なViewControllerを開くとき

```ViewController.swift
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if getIndexPathForSelectedCell() != nil {
            let newView = segue.destination as! DetailViewController
            newView.folderIndexPath = getIndexPathForSelectedCell()!
            newView.dataSource = self.dataSource
        }
    }
    
```

```DetailViewController.swift
    var folderIndexPath:IndexPath
    var dataSource:DataSource

    init(_ folderIndexPath:IndexPath, _ dataSource:DataSource) {
        self.folderIndexPath = folderIndexPath
        self.dataSource = dataSource
    }
```
ここでは、DataSourceクラスはViewControllerのどこかでinitializeされていて、それをDetailViewControllerにパスしています。

### 2. AppDelegateにあらかじめDIしておく

```AppDelegate.swift
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        
        
        //dependency injection
        let rootViewController = window?.rootViewController as! UINavigationController
        let photoViewController = rootViewController.topViewController as! PhotoViewController
        
        photoViewController.store = PhotoStore()
        
        return true
    }
```

```PhotoViewController.swift
    var store:PhotoStore!
```

ここではAppDelegateから画面に現れる最初のViewControllerを指定してます。いつもはViewControllerが勝手に出ますが、ここではPhotoViewControllerを出すように指示しています。
そのほかに、PhotoStoreクラスのinitializeもここで行なって、PhotoViewControllerにDI(注入)しています。



参考!
[猿でも分かる! Dependency Injection: 依存性の注入](http://qiita.com/hshimo/items/1136087e1c6e5c5b0d9f)
[Dependency Injection in Swift](https://medium.com/ios-os-x-development/dependency-injection-in-swift-a959c6eee0ab)