uitabbarcontroller reload after login with FirebaseAuth

追記。書きましたがログイン済みユーザーの場合、Observe（Listen）が2回走ってしまう（ViewControllerのviewDidLoadが2回呼ばれるため）のでおかしくなりますし、やはりListenはviewWillAppearでやるのが正しいみたいです。
https://firebase.googleblog.com/2015/10/best-practices-for-ios-uiviewcontroller_6.html

ただタブ遷移で毎回Listenとremoveを繰り返してしまいますので、これを辞めたい場合は別の方法で回避する必要がありそうです。

一応しばらく残して置きますが、後ほど消すか書き直します。

## 前提
タブバーのあるアプリでFirebaseAuthを使ったログインを実装。Initial View をMyTabBarControllerにしている。ホームとしてMyTabBarControllerの最初のViewをViewControllerにしている。

もしユーザー認証されていなかったら、LoginView/SignUpViewをPresentModallyで開いて、ログイン完了したらdissmissで閉じる仕様（その方がログイン済みユーザーにとっては余計なparentや処理がないかなと思って）。

### viewのライフサイクルのおさらい
![https___qiita-image-store.s3.amazonaws.com_0_326574_354ea62b-ca5a-1136-4524-de841e7d7b89.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242610/95e273fd-ffef-7e93-c778-e73abfe8f039.png)


## ログイン後にホームのcollectionViewが更新されない
Initial View にしているMyTabBarControllerと、その子のViewControllerのviewDidLoad, viewDidAppearは最初に呼ばれる。ログイン後にdissmissしても、子であるViewControllerのviewDidLoadやviewWillAppear, viewDidAppearは呼ばれない。そこでログインしたらMyTabBarControllerか、その子をリロード（初期化）してやる必要があった。

## 解決方法

dismiss後のMyTabBarControllerのviewDidAppearにて最初の子供だけリロードしてやった。

```swift
override func viewDidAppear(_ animated: Bool) {
		super.viewDidAppear(animated)
		guard let _ = Auth.auth().currentUser else {
			self.presentWelcomeView()
			return
		}
		self.viewControllers?.first?.loadView()
		self.viewControllers?.first?.viewDidLoad()
	}
```

## 全体のコード

```MyTabBarController.swift
import UIKit
import FirebaseAuth

class MyTabBarController: UITabBarController {

    override func viewDidLoad() {
        super.viewDidLoad()
    }
	
    override func viewDidAppear(_ animated: Bool) {
		super.viewDidAppear(animated)
		guard let _ = Auth.auth().currentUser else {
			self.presentWelcomeView() // ここで呼ばないと whose view is not in the window hierarchy! のエラーが出て怒られる（viewDidLoadではViewはロードされただけで生成はされてないかららしい）
			return
		}
//		self.setViewControllers(self.viewControllers, animated: true) //これではダメ
		self.viewControllers?.first?.loadView()
		self.viewControllers?.first?.viewDidLoad()
    }

    func presentWelcomeView() {
		guard let controller = storyboard?.instantiateViewController(identifier: "WelcomeNavigation") else { return }
		controller.modalPresentationStyle = .fullScreen
		self.present(controller, animated: true, completion: nil)
	}
}
```

```ViewController.swift
import UIKit
import FirebaseAuth
import FirebaseFirestore

class ViewController: UIViewController {

    @IBOutlet weak var collectionView: UICollectionView!
    
    var posts: [Post] = []
    
    var user: User!
    let db = Firestore.firestore()
    var userRef: DocumentReference? = nil
	var listener: ListenerRegistration?
                
    override func viewDidLoad() {
        super.viewDidLoad()
		guard let user = Auth.auth().currentUser else {
			return
		}
		self.user = user
		self.userRef = db.collection("users").document(self.user.uid)
        startObservingDatabase() // 省略：addSnapshotListenerによるリッスン処理
        self.collectionView.delegate = self
        self.collectionView.dataSource = self
    }
		    
	override func viewWillAppear(_ animated: Bool) {
		super.viewWillAppear(animated)
                // 公式ではここでAuth.auth().currentUserを読んでいる
                // しかしここはタブを押すたびに呼ばれるので毎回collectionViewが最新に更新されて本意ではない
	}
	
	override func viewWillDisappear(_ animated: Bool) {
		super.viewWillDisappear(animated)
		self.listener?.remove()
	}
}

```

```LoginViewController.swift
import UIKit
import FirebaseAuth

class LoginViewController: UIViewController {

    func signIn() {
		//if let tabvc = self.navigationController?.parent as? UITabBarController { // ここがそもそもnilでダメ
		//	tabvc.viewControllers?.first?.loadView()
		//	tabvc.viewControllers?.first?.viewDidLoad()
		//}
		self.navigationController?.dismiss(animated: true, completion: nil) // 今回はたまたま親にNavigationControllerを持たせていたので、ないならself.dismissでもOKなはず
    }
}
```

## 参考
- https://qiita.com/yamatatsu10969/items/58511c4982ba0cb11318