Firebaseでデータの呼び出しをしよう！

こんにちは！🐶

今まではデータの送信について学んできましたが、今回はデータの呼び出しについて学んでいきます！

#下準備
今回は、以前Postコレクションに送ったデータを、タイムライン画面に呼び出します！
そのために、以前作ったタイムライン画面にtableViewを配置しましょう！
![スクリーンショット 2021-06-09 0.41.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/694910/57a70161-cf04-f518-023e-b2958a630b68.png)

今回は、tableViewのcell をカスタムセルにするので、新しくカスタムセルのクラスとstorybordを作ります！作り方はFile作成時にSubclass ofをUITableViewCellに設定しましょう！そして、storybordも作りたいので、Also create XIB fileにチェックを入れてください！
![スクリーンショット 2021-06-09 0.45.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/694910/ca506057-b095-f2a0-3e7d-a85790ed90bd.png)
これでカスタムセル が作れました！

そして作ったカスタムセル （TableViewCell)をこのようなデザインにしてください！👇
ユーザー画像のimageViewとユーザネームのlabel,投稿画像のimageViewと投稿内容のtextViewを配置してます！👇
![スクリーンショット 2021-06-09 10.44.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/694910/2ac8d4f1-1963-633b-6e00-808392130409.png)

そして,viewControllerにtableVireの設定と前回同様必要なものをimportし、Firestoreのデータベースの変数も作ってあげましょう！👇


```php:ViewContoroller
import UIKit
import Firebase
import FirebaseAuth


class ViewController: UIViewController {
　　　@IBOutlet var timelineTableView : UITableView!
    //Firestoreのデータベース
    let db = Firestore.firestore()
    
    override func viewDidLoad() {
        super.viewDidLoad()
　　　　　//tableviewの設定
        timelineTableView.delegate = self
        timelineTableView.dataSource = self
        timelineTableView.register(UINib(nibName: "TimelineTableViewCell", bundle: nil), forCellReuseIdentifier: "Cell")
    }

    func loadPost() {
        
    }
}

//tableVIewの設定
extension ViewController : UITableViewDelegate,UITableViewDataSource {
    
//tableViewのcellの数
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    //postArrayに入れた配列の数だけセルを表示
    return postArray.count
}
//tableViewCellの中身
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
          let cell = timelineTableView.dequeueReusableCell(withIdentifier: "Cell") as! TimelineTableViewCell
            cell.postTextView.text = postArray[indexPath.row].postText
            return cell
       
    }
//tablaViewの高さ設定
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {  
         return 500
       }
}

```
今回はカスタムセルを使っているので、TabaleViewCellにも以下のように設定を行います！

```php:TabaleViewCell
class TimelineTableViewCell: UITableViewCell {
    
    @IBOutlet var postTextView : UITextView!
    @IBOutlet var userNameLabel : UILabel!
    @IBOutlet var userImageView : UIImageView!
    @IBOutlet var postImageView : UIImageView!
    
    
    
    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }
    
    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)
        
        // Configure the view for the selected state
    }
    
}
```

あともう一つの準備として、Nukeというライブラリをpodにinstallしましょう！
これは、あとでPostコレクションから持ってきたURLをNukeを使って、画像に変換するのに使います！
以下をpodに記入しinstallしてください！

```php:pod
pod 'Nuke'
```
#データを呼び出そう!
それでは、早速データ呼び出しのコードを書いていきたいと思います！

まず初めに流れを説明すると、
１データを呼び出す
２呼び出したデータを配列に入れる
３配列の情報をtableviewに表示する

この順番でいきたいと思います！

では、最初にデータを呼び出しましょう！
データを呼び出す関数を書き、その中でデータを呼び出します！
呼び出し方は以下になります。👇

```php:ViewContoroller
func loadPost() {
       //日付が古いものを下にして持ってくる
        db.collection("Post").order(by: "date").getDocuments  { (result, error) in
            if error != nil {
                print("データ呼び出し失敗")
            } else {
                print("データ呼び出し成功")
            }
        }
        
    }
```
まず,今回のタイムラインのように複数の情報（投稿）を持ってきたい時は、db.collection("Post").getDocumentsと表します。単一の情報を取得したい時はdb.collection("Post").getDocument（getDocumentsのsが無い）となります！
これで、resultの中にデータが入りました！

#呼び出したデータを配列の中に入れる
では次は、呼び出したデータをタイムラインのtableViewに表示させるには、配列を用意しその配列の中にデータを入れてあげなければなりません。
ですので、配列を用意するのですが、その前に、持ってきた情報を入れる用の構造体を作りましょう！

構造体とは、複数ある値をセットで保管できるものになります。
例えば、今回で言うと、Postコレクションからデータを持ってくるのですが、持ってくる情報は、テキストや画像など複数あります。それを構造体なしに持ってこようとすると、テキスト用の配列を用意して、画像用の配列を用意して。。。。ととても、面倒なものになってしまいます。
構造体を使うことで、1つの配列だけでで複数の情報を持ってくることができます！

では実際に構造体を作ってみましょう！
作り方はFile作成時　swiftfile ＞Nextを選択し、名前をPostとして保存しましょう。

![スクリーンショット 2021-06-09 0.48.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/694910/d48dd4b8-6717-1874-8ccf-02d11cdeea5f.png)

すると新しくファイルができました。この中に、Postコレクションから持ってきたい情報を書いていくとこんな感じになります👇


```php:Post
import Foundation
struct Post {
    let userImage: String
    let userName : String
    let postText : String
    let postImage : String
    let userId : String
}

```

これで構造体はできました！
そして、これを使い、配列の中にデータを入れていきましょう！

まず、コードは以下になります

```php:ViewContoroller
        db.collection("Post").getDocuments { (result, error) in
            if error != nil {
                print("データ呼び出し失敗")
            } else {
                print("データ呼び出し成功")
                
                if let documents = result?.documents {
                    //配列の初期化
                    self.postArray = []
                    //持ってきたデータを一つ一つ配列に入れる
                    for document in documents {
                        let data = document.data()
                        let post = Post(postText: data["text"] as! String, postImage: data["imageUrl"] as! String,userId:data["userId"] as! String)
                        //古いものを下にする
                        self.postArray.reverse()
                        //postArray配列に追加
                        self.postArray.append(post)
                        
                    }
                }
                
            }
        }
        
    }
```
ここは考えるというよりはやり方を覚えてもらう感じでOKです。説明すると、先ほど作った構造体Postに従って、データを持ってきます。””はFiretoreのドキュメントの中のフィールド名を指します。👇
![スクリーンショット 2021-06-08 13.54.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/694910/6d6e680e-642e-909c-5844-884571da756e.png)

こうすることで投稿内容と投稿の画像を持ってくることができました！

#tabaleViewに表示させよう！
情報が持って来れたら次はtableViewに表示させましょう！では,extensionでtableViewの設定を行いましょう！👇

```php:ViewContoroller
extension ViewController : UITableViewDelegate,UITableViewDataSource {
    
//tableViewのcellの数
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    //postArrayに入れた配列の数だけセルを表示
    return postArray.count
}
//tableViewCellの中身
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
          let cell = timelineTableView.dequeueReusableCell(withIdentifier: "Cell") as! TimelineTableViewCell
            cell.postTextView.text = postArray[indexPath.row].postText
            return cell
       
    }
}
 ```
こうすることで、cellのpostTextViewには投稿内容が入りました！

では、次は画像を呼び出しましょう！
呼び出す画像は投稿画像とユーザー画像になります！ここで先ほど、podに入れたNukeを使うのでimportしておいてください！

最初に完成形を見せます！👇

```php:ViewContoroller
//tableViewCellの中身
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = timelineTableView.dequeueReusableCell(withIdentifier: "Cell") as! TimelineTableViewCell
        cell.postTextView.text = postArray[indexPath.row].postText
        //投稿画像をセルに配置
        //Nukeを使いURLから画像に変更してセルのimageUrlに入れる
        let imageUrl = URL(string: postArray[indexPath.row].postImage)
        Nuke.loadImage(with: imageUrl as! ImageRequestConvertible , into: cell.postImageView)
        
        //ユーザー画像をセルに配置
        db.collection("Users").document(postArray[indexPath.row].userId).getDocument { (result, error) in
            if error != nil {
                print("ユーザー情報取得失敗")
            }
            print("ユーザー情報取得成功")
            let data = result!.data()
            let user = User(userName: data!["userName"] as! String, profileImage: data!["profilrImage"]  as! String, introduction: data!["introduction"] as! String)
            cell.userNameLabel.text = user.userName
            //ユーザー画像が設定されていれば
            if let userImageUrl = URL(string:user.profileImage ?? "") {
                Nuke.loadImage(with: userImageUrl, into: cell.userImageView)
            }
  
        }
        return cell
    }
 ```

分解して解説すると、まず投稿用の画像を持ってくるときはこのように書きます。👇

```php:ViewContoroller
//tableViewCellの中身
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
          let cell = timelineTableView.dequeueReusableCell(withIdentifier: "Cell") as! TimelineTableViewCell
          cell.postTextView.text = postArray[indexPath.row].postText
           //Nukeを使いURLから画像に変更してセルのimageUrlに入れる
          let imageUrl = URL(string: postArray[indexPath.row].postImage)
          Nuke.loadImage(with: imageUrl , into: cell.postImageView)
       
    }
}
 ```
Nukeで以前保存したPostコレクションの中にあるimageをURLから画像に変換し、それをセルのimageViewに入れています。

次に、ユーザー画像を持ってきましょう。このようになります👇

```php:ViewContoroller
//tableViewCellの中身
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
　//投稿画像を持ってくるコード


        
  //ユーザー画像をを持ってくる
//ユーザーコレクションからドキュメントか投稿した人のユーザーIDと一致するものを持ってくる
  db.collection("Users").document(postArray[indexPath.row].userId).getDocument { (result, error) in
            if error != nil {
                print("ユーザー情報取得失敗")
            }
            print("ユーザー情報取得成功")
            let data = result!.data()
            //Userモデル（構造体）を作り、その中に値を入れる
            let user = User(userName: data!["userName"] as! String, profileImage: data!["profilrImage"]  as! String, introduction: data!["introduction"] as! String)
            cell.userNameLabel.text = user.userName
            //ユーザー画像が設定されていれば
            if let userImageUrl = URL(string:user.profileImage ?? "") {
                Nuke.loadImage(with: userImageUrl, into: cell.userImageView)
            }
  
        }
        return cell
    }
 ```

となります！ですので、ユーザ画像を持ってくる際は、新しくUserモデル（構造体）を作りましょう！作り方は以前説明した通りで、まず、File作成時　swiftfile ＞Nextを選択し、名前をUserとして保存しましょう。

その中に持ってきたいユーザー情報を書きましょう👇

```php:User
struct User {
    
let userName: String
let profileImage : String
let introduction : String
    
}
```
こうする事で、ユーザー情報を持ってくる際にこのUserモデルを使うことによって、簡単に欲しい情報を格納することができます！

はい！では、今まで作ってきたものを関連づけしたら、このようにタイムラインに投稿が表示されましたーー！！！

#お疲れ様でした！
今回は、データ情報を持ってくるということをしました！
これでFirestoreの基本的な機能は実装することができたと思います！８８８８
![スクリーンショット 2021-06-09 13.56.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/694910/319b6ccf-808e-ce28-19d8-15a650291442.png)

まだユーザー画像は設定してないので空白の状態です。
ですので、次回は、ユーザープロフィール編集、つまりデータの更新についてやっていきます！