static cellとcontainerを利用して、controllerを分割する実験


### 概要
いくつかのcontainer viewの表示と非表示の切り替えを行う。
縦に切り替えを行うためにtable view controllerのcellの高さを調節する。

https://github.com/reikubonaga/containerSample1

### container view controllerの表示

* static table Cell上にcontainerを設置。
* containerにviewControllerをセットして表示する。
* cellかどうかの判定は、cellの比較によって判定し、heightは自分で定義する。

```
static CGFloat const kViewControllerCellHeight = 300;

@property (nonatomic, weak) IBOutlet UITableViewCell *viewControllerCell;

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];

    if (cell == self.viewControllerCell) {
        return kViewControllerCellHeight;
    }

    return 0;
}
```

### container view controllerの表示の切り替え
* cellの表示・非表示の処理
* 表示・非表示用のpropertyを追加する

```
@property (nonatomic, assign, getter = isViewControllerCellHidden) BOOL viewControllerCellHidden;

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];

    if (cell == self.viewControllerCell && !self.isViewControllerCellHidden) {
        return kViewControllerCellHeight;
    }

    return 0;
}
```

### ライフサイクル

高さが300に指定した場合(画面内に収まる)

1. WTDTableViewController prepareForSegue
- WTDContainerViewController viewDidLoad
- WTDTableViewController viewDidLoad
- WTDTableViewController viewWillAppear
- WTDTableViewController viewWillLayoutSubviews
- WTDTableViewController heightForRowAtIndexPath
- WTDContainerViewController viewWillAppear
- WTDTableViewController viewDidLayoutSubviews
- WTDTableViewController viewWillLayoutSubviews
- WTDTableViewController viewDidLayoutSubviews
- WTDContainerViewController viewWillLayoutSubviews
- WTDContainerViewController viewDidLayoutSubviews
- WTDTableViewController viewDidAppear
- WTDContainerViewController viewDidAppear
- WTDContainerViewController viewDidAppear


高さを1000に指定した場合(画面からはみ出るcellの場合)

1. WTDTableViewController prepareForSegue
- WTDContainerViewController viewDidLoad
- WTDTableViewController viewDidLoad
- WTDTableViewController viewWillAppear
- WTDTableViewController viewWillLayoutSubviews
- WTDTableViewController heightForRowAtIndexPath
- WTDContainerViewController viewWillAppear
- WTDTableViewController viewDidLayoutSubviews
- WTDTableViewController viewWillLayoutSubviews
- WTDTableViewController viewDidLayoutSubviews
- WTDContainerViewController viewWillLayoutSubviews
- WTDContainerViewController viewDidLayoutSubviews
- WTDTableViewController viewDidAppear
- WTDContainerViewController viewDidAppear
- WTDContainerViewController viewDidAppear
- WTDTableViewController viewWillLayoutSubviews
- WTDTableViewController viewDidLayoutSubviews

※ またスクロールの度に
- WTDTableViewController viewWillLayoutSubviews
- WTDTableViewController viewDidLayoutSubviews
が呼ばれる

viewの非表示を実行した際の動作

1. WTDContainerViewController viewWillDisAppear
- WTDTableViewController heightForRowAtIndexPath
- WTDTableViewController viewWillLayoutSubviews
- WTDContainerViewController viewWillAppear
- WTDTableViewController viewDidLayoutSubviews
- WTDContainerViewController viewWillLayoutSubviews
- WTDContainerViewController viewDidLayoutSubviews
- WTDContainerViewController viewDidAppear

viewを再表示させた時の動作

1. WTDContainerViewController viewWillDisAppear
- WTDTableViewController heightForRowAtIndexPath
- WTDTableViewController viewWillLayoutSubviews
- WTDContainerViewController viewWillAppear
- WTDTableViewController viewDidLayoutSubviews
- WTDContainerViewController viewWillLayoutSubviews
- WTDContainerViewController viewDidLayoutSubviews
- WTDContainerViewController viewDidAppear

### (要件)containerViewControllerを表示された時にキーボードにフォーカスを当てる
1 viewWillApearでキーボードを開くことを呼び出す

```
- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    [self.textField resignFirstResponder];
}
```
※ cellの高さがあるときもないときもキーボードの呼び出しがされる。

2 viewControllerのframeの高さの変化をKVOで受け取る

```

- (void)viewDidLoad
{
    [super viewDidLoad];

    [self.view addObserver:self forKeyPath:NSStringFromSelector(@selector(frame)) options:NSKeyValueObservingOptionNew context:NULL];

    self.viewControllerCellHidden = YES;
}

#pragma mark - Key Value Observing

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if ([keyPath isEqualToString:NSStringFromSelector(@selector(frame))]) {
        fprintf(stderr, "call KVO\n");
        [self.containerViewController.textField becomeFirstResponder];
    }
}
```
※ KVOがcallされるのは、containerViewControllerのviewDidLoadが実行されるタイミングだけだった。

3 prepareForSegueでcontainerViewControllerをhiddenにして、heightForRowAtIndexPathでhiddenを解除する

``` TableViewController

#pragma mark - Table view data source
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    [super prepareForSegue:segue sender:sender];

    if ([[segue identifier] isEqualToString:kPushContainerViewController]) {
        self.containerViewController = [segue destinationViewController];
        self.containerViewController.view.hidden = YES;
    }
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];

    if (cell == self.viewControllerCell && !self.isViewControllerCellHidden) {
        self.containerViewController.view.hidden = NO;
        return kViewControllerCellHeight;
    } else {
        self.containerViewController.view.hidden = YES;
    }

    return 0;
}
```
``` ContainerViewController
- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    if (!self.view.hidden) {
        [self.textField becomeFirstResponder];
    } else {
        [self.textField resignFirstResponder];
    }
}

```
※ これであれば、判定は行える。

問題点

* UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
の処理って遅いのでは。
* cellの高さが0でも、containerの中ではviewのレンダーが行われているのが無駄かも。
* keyboardを出すときや、cellのheightのサイズが大きいときに、
WTDTableViewControllerのviewWillLayoutSubviewsとviewDidLayoutSubviewsがたくさん実行されている。
* 結局、containerViewControllerのコードを変えないとうまくキーボードを表示させることができなかった

今後考えたいこと

* そもそもtableViewControllerではなく、UIViewControllerでscrollViewを使う方がいいのかもしれない。両者を比較してみたい。
* 今回は、containerに、UIViewControllerを設置したが、UITableViewControllerを設置して、その中でviewの大きさが変わるときにどのように対処するかもまとめたい。
* そもそもviewの実行が何度も行われるから、containerを利用するべきでないのかもしれない。。

その後の検証
* static cellでなくscroll viewで実装
* constraintで高さを調整
* 問題としては今まではcontentSizeの変更で親viewの大きさを変える動作をさせていたが、それが動かなかった。blockを受け渡して必要なタイミングで更新するロジックに
* staticセルのように新しくcellを生成するタイミングでのひっかかりがなくなったが、逆にnavigation controllerを使って遷移するまでの時間は長くなった
* ひっかかりがあるほうがUXとして悪いという判断で大幅リファクタリングをした