【Swift】TableViewで検索したもののみ表示する

#はじめに
今回は検索した文字列のみTableViewで表示させてます。以下のようなものを作ってみます。
![ezgif.com-gif-maker.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954451/65e12b55-0fc4-4eda-1499-4814dc1f14c4.gif)

#GitHub
https://github.com/0429oonishi/TableViews

#実装
1.Main.storyboardで以下のように`UITextField`と`UITableView`を配置する。
![スクリーンショット 2021-03-31 20.01.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954451/2b5f9810-23cb-8eb9-206f-17a89ac6489d.png)
2.文字列を入れておく配列と、検索されたものを入れておく配列を用意する。

```swift:ViewController
private var datas = [String]()
private var filterdDatas = [String]()
```

3.先ほど用意した配列に`viewDidLoad()`でデータを格納する。

```swift:ViewController
datas.append("Swift")
datas.append("Java")
datas.append("Ruby")
datas.append("C++")
datas.append("C")
datas.append("C#")
datas.append("Python")
datas.append("Perl")
datas.append("JavaScript")
datas.append("PHP")
datas.append("Scratch")
datas.append("Scala")
datas.append("COBOL")
datas.append("Curl")
datas.append("Dart")
datas.append("HTML")
datas.append("CSS")
```
4.`delegate`を使う

```Swift:ViewController
tableView.delegate = self
tableView.dataSource = self
tableView.tableFooterView = UIView() // 不要なセパレーターが表示されなくなります
textField.delegate = self
```
5.`UITableViewDelegate`を実装

```swift:ViewController
extension ViewController: UITableViewDelegate {
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 60 //　適当に高さを60にしておきます
    }
}
```
6.`UITableViewDataSource`を実装

```swift:ViewController
extension ViewController: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if !filterdDatas.isEmpty {
            return filterdDatas.count
        }
        return datas.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        cell.textLabel?.text = filterdDatas.isEmpty ? datas[indexPath.row] : filterdDatas[indexPath.row]
        return cell
    }
}
```
`filterdDatas`が空だったら、`datas.count`を、何かしら入っていたら`filterdDatas.count`を返してあげます。

7.`UITextFieldDelegate`を実装

```swift:ViewController
extension ViewController: UITextFieldDelegate {
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        if let text = textField.text {
            (string.count == 0) ? filterText(String(text.dropLast())) : filterText(text+string)
        }
        return true
    }
    
    func filterText(_ query: String) {
        filterdDatas.removeAll()
        datas.forEach { data in
            if data.lowercased().starts(with: query.lowercased()) {
                filterdDatas.append(data)
            }
        }
        tableView.reloadData()
    }
}
```
`textField`のデリゲートメソッドである`shouldChangeCharactersIn`は文字が入力される度に処理が呼ばれるメソッドです([参考記事](https://qiita.com/cyan/items/ce299d1b2fefde4c068e))
`(string.count == 0) ? filterText(String(text.dropLast())) : filterText(text+string)`の`string`は入力した文字が一文字です。これが`0`つまり、`textField`の文字を消去した時に`text.dropLast()`します。([参考記事](https://developer.apple.com/documentation/swift/string/2893517-droplast))
`lowercased()`で大文字を全て小文字に変換しています。([参考記事](https://developer.apple.com/documentation/swift/string/1641392-lowercased))
`starts(with: )`でシーケンスの最初の要素が別のシーケンスの要素と同じであるかどうかをブール値で返します。つまり、大文字小文字を区別せずに、入力された値の`query`に`data`が完全に含まれていれば`true`になります。
そして、文字が入力されるたびに`tableView`を更新してあげます。

8.フラグを立てる
このままだと、検索結果がない時には全て表示されてしまいます。　
なので、フラグを立てて該当する文字があるかどうか判断します。

```swift:ViewController
private var isFilterd = false
```

そして、`tableView.reloadData()`の下に`isFilterd = true`を追加して、`numberOfRowsInSection`を`return isFilterd ? 0 : datas.count`に変更します。

#おわりに
おわりです。