自分が理解したいためにまとめました!間違いがあればぜひご指摘を。
1. Dependency Injection(DI)ってなんやねん。
意味を訳すと、Dependency = 依存で、
Injection = 注入、注射するです。つまり、
**「依存していた部分を、外から注入すること」**by @hshimoさん
つまり、外からオブジェクトを受け取ることです。
2. DIが便利なわけ / 使いたい理由
*@hshimo さんから言葉をお借りしてます
柔軟性がない -> 決め打ちなので、柔軟性がなくカスタマイズしにくい
テストしにくい -> 外から動的に動作を変更できないので、テストしづらい
ってイキナリ言われても解らんですよね。そこで例えを使って考えましょう。
3. 例で考える
たとえば、ドクターがいて、ナースさんがいて、カルテがあったら、普通はドクターがカルテを書いて、ナースさんに渡してそれを元に患者に対応しますよね?(DI後)
でも、医者がカルテ作成を全部ナースさんに丸投げしたらどうなるでしょうか? ナースさんはいちいちドクターに患者の状況を聞いてから、カルテを作成しないと行けないです。(DI前)
こうなると、ナースさんの仕事が増えてすごく大変。しかもカルテをドクターが直したい、となったら、ナースさんはまたイチから作成しないといけません。(DI前)
DI前のコード
protocol Carte {}
class Doctor{
func assignNurse() -> Nurse{
var nurse = Nurse()
return nurse
}
}
class Nurse {
let carte: Carte
init() {
carte = Carte()
}
}
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
}
}
var carte = doctor.makeCarte()
var nurse = Nurse(carte)
DI後コードでは、NurseクラスはCarteをinit(作成してない!)
そして外からcarteオブジェクトを注入にしているので、carteに変更があった場合、Nurseの中身は書き換えなくてもいいので、テストが楽。
DIがを使いたい理由を簡単に説明すると、
**一つのクラスが仕事を持ちすぎているので(クラス依存)、スムーズに事が進むように、仕事を分担する、という感じで。**ナースさんはカルテの中身を知りたいけど、作成方法は一切知らなくてもいい、という感じです。
え、例えとコードが微妙??ごめんなさい。
4. 色々なところで使うDependency Injection
1. Viewcontrollerから別なViewControllerを開くとき
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if getIndexPathForSelectedCell() != nil {
let newView = segue.destination as! DetailViewController
newView.folderIndexPath = getIndexPathForSelectedCell()!
newView.dataSource = self.dataSource
}
}
var folderIndexPath:IndexPath
var dataSource:DataSource
init(_ folderIndexPath:IndexPath, _ dataSource:DataSource) {
self.folderIndexPath = folderIndexPath
self.dataSource = dataSource
}
ここでは、DataSourceクラスはViewControllerのどこかでinitializeされていて、それをDetailViewControllerにパスしています。
2. AppDelegateにあらかじめDIしておく
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
}
var store:PhotoStore!
ここではAppDelegateから画面に現れる最初のViewControllerを指定してます。いつもはViewControllerが勝手に出ますが、ここではPhotoViewControllerを出すように指示しています。
そのほかに、PhotoStoreクラスのinitializeもここで行なって、PhotoViewControllerにDI(注入)しています。
参考!
猿でも分かる! Dependency Injection: 依存性の注入
Dependency Injection in Swift