62337
Xcode11.3  
Swift5  
macOSMojave10.14.6

# 実現したいことと

フェイスブックのコメントボタンを押した時のような、UITableViewを使用したタイムライン画面(HomeViewController)から個別の画面(ArticleViewController)に遷移（画像１）  
↓  
(ArticleViewContorollerの)TextFieldにコメントを入力後、投稿ボタンを押すと、遷移前のタイムライン画面（HomeViewController）でタップしたセルと同じセル番号にコメント文がFirebase(commnets)に追加され（画像２）、遷移後の画面(ArticleViewController)にあるテーブルビュー（commentTableView,CommentTableViewCell）にコメントが表示される  
↓  
別のユーザーがコメント投稿するごとに下に増えていく  
[![画像の説明をここに入力](https://i.stack.imgur.com/p4HHc.jpg)](https://i.stack.imgur.com/p4HHc.jpg)

# 困っていること

Farebaseにはタイムラインの記事ごとにコメントが格納されますが、そこからカスタムセル（CommenTabaleViewCell）で記事ごとのコメントデータを表示せず、全てのコメントが表示されてしまい、他の記事を表示しても同じコメントになってしまいます。  
ArticleViewControllerからCommentTableViewCellへのindexPathの渡し方が悪いと思いますが、ご教授願います。  
[![firebaseには](https://i.stack.imgur.com/gCq50.png)](https://i.stack.imgur.com/gCq50.png)  
firebaseには孫データ（comments）が反映されています。

**タイムライン画面**

```

    import UIKit
    import Firebase
    
    class HomeViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
    
        @IBOutlet weak var tableView: UITableView!
    
        var postArray: [PostData] = []
    
        // DatabaseのobserveEventの登録状態を表す
        var observing = false
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            tableView.delegate = self
            tableView.dataSource = self
    
            let nib = UINib(nibName: "PostTableViewCell", bundle: nil)
            tableView.register(nib, forCellReuseIdentifier: "Cell")
    
            // テーブル行の高さを165
            tableView.rowHeight = 165
            // テーブル行の高さの概算値を設定しておく
            // 高さ概算値 = 「縦横比1:1のUIImageViewの高さ(=画面幅)」+「いいねボタン、キャプションラベル、その他余白の高さの合計概算(=100pt)」
            tableView.estimatedRowHeight = UIScreen.main.bounds.width
        }
    
        override func viewWillAppear(_ animated: Bool) {
            super.viewWillAppear(animated)
            print("DEBUG_PRINT: viewWillAppear")
    
            if Auth.auth().currentUser != nil {
                if self.observing == false {
                    // 要素が追加されたらpostArrayに追加してTableViewを再表示する
                    let postsRef = Database.database().reference().child(Const.PostPath)
                    postsRef.observe(.childAdded, with: { snapshot in
                        print("DEBUG_PRINT: .childAddedイベントが発生しました。")
    
                        // PostDataクラスを生成して受け取ったデータを設定する
                        if let uid = Auth.auth().currentUser?.uid {
                            let postData = PostData(snapshot: snapshot, myId: uid)
                            self.postArray.insert(postData, at: 0)
    
                            // TableViewを再表示する
                            self.tableView.reloadData()
                        }
                    })
                    // 要素が変更されたら該当のデータをpostArrayから一度削除した後に新しいデータを追加してTableViewを再表示する
                    postsRef.observe(.childChanged, with: { snapshot in
                        print("DEBUG_PRINT: .childChangedイベントが発生しました。")
    
                        if let uid = Auth.auth().currentUser?.uid {
                            // PostDataクラスを生成して受け取ったデータを設定する
                            let postData = PostData(snapshot: snapshot, myId: uid)
    
                            // 保持している配列からidが同じものを探す
                            var index: Int = 0
                            for post in self.postArray {
                                if post.id == postData.id {
                                    index = self.postArray.firstIndex(of: post)!
                                    break
                                }
                            }
    
                            // 差し替えるため一度削除する
                            self.postArray.remove(at: index)
    
                            // 削除したところに更新済みのデータを追加する
                            self.postArray.insert(postData, at: index)
    
                            // TableViewを再表示する
                            self.tableView.reloadData()
                        }
                    })
    
                    // DatabaseのobserveEventが上記コードにより登録されたため
                    // trueとする
                    observing = true
                }
            } else {
                if observing == true {
                    // ログアウトを検出したら、一旦テーブルをクリアしてオブザーバーを削除する。
                    // テーブルをクリアする
                    postArray = []
                    tableView.reloadData()
                    // オブザーバーを削除する
                    let postsRef = Database.database().reference().child(Const.PostPath)
                    postsRef.removeAllObservers()
    
                    // DatabaseのobserveEventが上記コードにより解除されたため
                    // falseとする
                    observing = false
                }
            }
        }
        //セルの数を決めるメソッド
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return postArray.count
        }
        //セルを構築する際に呼ばれるメソッド
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            // セルを取得してデータを設定する
            let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! PostTableViewCell
            cell.setPostData(postArray[indexPath.row])
    
            // セル内のボタンのアクションをソースコードで設定する
            cell.likeButton.addTarget(self, action:#selector(handleButton(_:forEvent:)), for: .touchUpInside)
    
            return cell
        }
    
        //セルをタップしたら...のメソッド
        func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    
            // タップされたセルの行番号を出力
            print("\(indexPath.row)番目の行が選択されました。")
    
            let postData = postArray[indexPath.row]
    
            postDataToSend = postData
                performSegue(withIdentifier: "Article", sender: nil)
                //セルの選択を解除
                tableView.deselectRow(at: indexPath, animated: true)
    
            }
    
            var postDataToSend: PostData?
    
            override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
                if segue.identifier == "Article" {
                    let nextVC = segue.destination as! ArticleViewController
                    if let postData = postDataToSend {
                        nextVC.setPostData(postData)
                    }
                }
        }
    
        // セル内のボタンがタップされた時に呼ばれるメソッド
        @objc func handleButton(_ sender: UIButton, forEvent event: UIEvent) {
            print("DEBUG_PRINT: likeボタンがタップされました。")
    
            // タップされたセルのインデックスを求める
            let touch = event.allTouches?.first
            let point = touch!.location(in: self.tableView)
            let indexPath = tableView.indexPathForRow(at: point)
    
            // 配列からタップされたインデックスのデータを取り出す
            let postData = postArray[indexPath!.row]
    
            // Firebaseに保存するデータの準備
            if let uid = Auth.auth().currentUser?.uid {
                if postData.isLiked {
                    // すでにいいねをしていた場合はいいねを解除するためIDを取り除く
                    var index = -1
                    for likeId in postData.likes {
                        if likeId == uid {
                            // 削除するためにインデックスを保持しておく
                            index = postData.likes.firstIndex(of: likeId)!
                            break
                        }
                    }
                    postData.likes.remove(at: index)
                } else {
                    postData.likes.append(uid)
                }
    
                // 増えたlikesをFirebaseに保存する
                let postRef = Database.database().reference().child(Const.PostPath).child(postData.id!)
                let likes = ["likes": postData.likes]
                postRef.updateChildValues(likes)
    
            }
        }   
    }
    
```

**コメント投稿画面**

```

    import UIKit
    import Firebase
    import SVProgressHUD
    
    class ArticleViewController: UIViewController,UITextFieldDelegate, UITableViewDataSource, UITableViewDelegate {
    
        @IBOutlet weak var articleImage: UIImageView!
        @IBOutlet weak var articleLabel: UILabel!
        @IBOutlet weak var articleButton: UIButton!
        @IBOutlet weak var articleLilkeCount: UILabel!
        @IBOutlet weak var commentTextField: UITextField!
        @IBOutlet weak var commentTableView: UITableView!
    
        var postArray: [PostData] = []
        //textFieldが動くようにする
        private var activeTextField: UITextField?
    
        //前画面からデータを受け取るための変数
        var postDataReceived: PostData?
    
        // DatabaseのobserveEventの登録状態を表す
        var observing = false
    
        override func viewWillAppear(_ animated: Bool) {
            super.viewWillAppear(animated)
    
            commentTableView.delegate = self
            commentTableView.dataSource = self
            // テーブルセルのタップを無効にする
            commentTableView.allowsSelection = false
    
            guard let postData = postDataReceived else {
                return
            }
            let nib = UINib(nibName: "CommentTableViewCell", bundle: nil)
            commentTableView.register(nib, forCellReuseIdentifier: "Cell2")
    
            // テーブル行の高さをAutoLayoutで自動調整する
            commentTableView.rowHeight = UITableView.automaticDimension
            // テーブル行の高さの概算値を設定しておく
            // 高さ概算値 = 「縦横比1:1のUIImageViewの高さ(=画面幅)」+「いいねボタン、キャプションラベル、その他余白の高さの合計概算(=100pt)」
            commentTableView.estimatedRowHeight = UIScreen.main.bounds.width
    
            //イメージ画像
            self.articleImage.image = postData.image
            //キャプションのテキスト
            self.articleLabel.text = "\(postData.caption!)"
            //いいねの数
            let likeNumber = postData.likes.count
            articleLilkeCount.text = "\(likeNumber)"
    
    
            if Auth.auth().currentUser != nil {
                if self.observing == false {
                    // 要素が追加されたらpostArrayに追加してTableViewを再表示する
                    let postsRef = Database.database().reference().child(Const.PostPath)
                    postsRef.observe(.childAdded, with: { snapshot in
                        print("DEBUG_PRINT: .childAddedイベントが発生しました。")
    
                        // PostDataクラスを生成して受け取ったデータを設定する
                        if let uid = Auth.auth().currentUser?.uid {
                            let postData = PostData(snapshot: snapshot, myId: uid)
                            self.postArray.insert(postData, at: 0)
    
                            // TableViewを再表示する
                            self.commentTableView.reloadData()
                        }
                    })
                    // 要素が変更されたら該当のデータをpostArrayから一度削除した後に新しいデータを追加してTableViewを再表示する
                    postsRef.observe(.childChanged, with: { snapshot in
                        print("DEBUG_PRINT: .childChangedイベントが発生しました。")
    
                        if let uid = Auth.auth().currentUser?.uid {
                            // PostDataクラスを生成して受け取ったデータを設定する
                            let postData = PostData(snapshot: snapshot, myId: uid)
    
                            // 保持している配列からidが同じものを探す
                            var index: Int = 0
                            for post in self.postArray {
                                if post.id == postData.id {
                                    index = self.postArray.firstIndex(of: post)!
                                    break
                                }
                            }
    
                            // 差し替えるため一度削除する
                            self.postArray.remove(at: index)
    
                            // 削除したところに更新済みのデータを追加する
                            self.postArray.insert(postData, at: index)
    
                            // TableViewを再表示する
                            self.commentTableView.reloadData()
                        }
                    })
    
                    // DatabaseのobserveEventが上記コードにより登録されたため
                    // trueとする
                    observing = true
                }
            } else {
                if observing == true {
                    // ログアウトを検出したら、一旦テーブルをクリアしてオブザーバーを削除する。
                    // テーブルをクリアする
                    postArray = []
                    commentTableView.reloadData()
                    // オブザーバーを削除する
                    let postsRef = Database.database().reference().child(Const.PostPath)
                    postsRef.removeAllObservers()
    
                    // DatabaseのobserveEventが上記コードにより解除されたため
                    // falseとする
                    observing = false
                }
            }
    
            //textFieldがキーボードで隠れないようにする
            self.commentTextField.delegate = self
            self.setUpNotificationForTextField()
        }
        func setPostData(_ postData: PostData) {
            postDataReceived = postData
        }
        //textFieldがキーボードで隠れないようにする
        internal func textFieldShouldReturn(_ textField: UITextField) -> Bool {
               textField.resignFirstResponder()
               return true
           }
        //textFieldがキーボードで隠れないようにする
        internal func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
            self.activeTextField = textField
            return true
        }
        //textFieldがキーボードで隠れないようにする
         internal func setUpNotificationForTextField() {
               let notificationCenter = NotificationCenter.default
               notificationCenter.addObserver(self, selector: #selector(self.handleKeyboardWillShowNotification(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
               notificationCenter.addObserver(self, selector: #selector(self.handleKeyboardWillHideNotification(_:)), name: UIResponder.keyboardWillHideNotification, object: nil)
           }
        //textFieldがキーボードで隠れないようにする
        @objc private func handleKeyboardWillShowNotification(_ notification: Notification) {
            let userInfo = notification.userInfo //この中にキーボードの情報がある
            let keyboardSize = (userInfo![UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
            let keyboardY = self.view.frame.size.height - keyboardSize.height //画面全体の高さ - キーボードの高さ = キーボードが被らない高さ
            let editingTextFieldY: CGFloat = (self.activeTextField?.frame.origin.y)!
            if editingTextFieldY > keyboardY - 60 {
                UIView.animate(withDuration: 0.25, delay: 0.0, options: .curveEaseIn, animations: {
                    self.view.frame = CGRect(x: 0, y: self.view.frame.origin.y - (editingTextFieldY - (keyboardY - 60)), width: self.view.bounds.width, height: self.view.bounds.height)
                }, completion: nil)
    
            }
        }
        //textFieldがキーボードで隠れないようにする
        @objc private func handleKeyboardWillHideNotification(_ notification: Notification) {
            UIView.animate(withDuration: 0.25, delay: 0.0, options: .curveEaseIn, animations: {
                self.view.frame = CGRect(x: 0, y: 0, width: self.view.bounds.width, height: self.view.bounds.height)
            }, completion: nil)
        }
        //コメントテーブルビュー
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
               return postArray.count
           }
    
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
           // セルを取得してデータを設定する
           let cell2 = tableView.dequeueReusableCell(withIdentifier: "Cell2", for: indexPath) as! CommentTableViewCell
           cell2.commentSetPostData(postArray[indexPath.row])
    
            //テキストを初期化
            cell2.commentLabel.text = nil
    
           // セル内のボタンのアクションをソースコードで設定する
           cell2.goodButton.addTarget(self, action:#selector(handleGoodButton(_:forEvent:)), for: .touchUpInside)
    
           return cell2
        }
        //コメント投稿ボタン
        @IBAction func commentButton(_ sender: UIButton) {
            // 前画面から受け取ったデータを取り出す
            guard let postData = postDataReceived else {
                return
            }
    
            //cell.textField.textがnilじゃなかったら、commentTextとする
            if let commentText = self.commentTextField.text  {
    
                //であれば、cell(PostTableViewCell)のtextFieldをプリントする
                print(self.commentTextField.text as Any)
    
                //であれば、postData.commentsにcommentTextをappend(追加)する
                postData.comments.append("\(commentText)\n")
            }
    
            // 増えたcommentsをFirebaseに保存する
            let postRef = Database.database().reference().child(Const.PostPath).child(postData.id!)
            //comments辞書
            let commentDictionary = ["comments": postData.comments]
            //Firebaseに辞書を保存する
            postRef.updateChildValues(commentDictionary)
        }
    
        // セル内のボタンがタップされた時に呼ばれるメソッド
        @objc func handleGoodButton(_ sender: UIButton, forEvent event: UIEvent) {
            print("DEBUG_PRINT: goodボタンがタップされました。")
    
            // タップされたセルのインデックスを求める
            let touch = event.allTouches?.first
            let point = touch!.location(in: self.commentTableView)
            let indexPath = commentTableView.indexPathForRow(at: point)
    
            // 配列からタップされたインデックスのデータを取り出す
            let postData = postArray[indexPath!.row]
    
            // Firebaseに保存するデータの準備
            if let uid = Auth.auth().currentUser?.uid {
                if postData.isLiked2 {
                    // すでにいいねをしていた場合はいいねを解除するためIDを取り除く
                    var index = -1
                    for likeId in postData.likes2 {
                        if likeId == uid {
                            // 削除するためにインデックスを保持しておく
                            index = postData.likes2.firstIndex(of: likeId)!
                            break
                        }
                    }
                    postData.likes2.remove(at: index)
                } else {
                    postData.likes2.append(uid)
                }
    
                // 増えたgoodをFirebaseに保存する
                let postRef = Database.database().reference().child(Const.PostPath).child(postData.id!)
                let goods = ["likes2": postData.likes2]
                postRef.updateChildValues(goods)
    
            }
        }
    }
    
    
```

**カスタムセル**

```

    class CommentTableViewCell: UITableViewCell {
    
        @IBOutlet weak var commentLabel: UILabel!
        @IBOutlet weak var goodButton: UIButton!
        @IBOutlet weak var countLabel: UILabel!
    
        //前画面からデータを受け取るための変数
        var postDataReceived: PostData?
    
        override func awakeFromNib() {
            super.awakeFromNib()
            // Initialization code
        }
    
        override func setSelected(_ selected: Bool, animated: Bool) {
            super.setSelected(selected, animated: animated)
    
        }
    
        func commentSetPostData(_ postData: PostData) {
            postDataReceived = postData
    
            //postData.commentsの中から要素をひとつずつ取り出すのを繰り返す、というのがcomment
            for comment in postData.comments{
                //commentLabelに表示するのはcomment
                self.commentLabel.text = comment
            }
        }
    }
    
```

**ポストデータ**

```

    import UIKit
    import Firebase
    
    class PostData: NSObject {
        var id: String?
        var image: UIImage?
        var imageString: String?
        var name: String?
        var caption: String?
        var comments : [String] = []
        var date: Date?
        var likes: [String] = []
        var isLiked: Bool = false
        var likes2: [String] = []
        var isLiked2: Bool = false
    
        init(snapshot: DataSnapshot, myId: String) {
            self.id = snapshot.key
    
            let valueDictionary = snapshot.value as! [String: Any]
            //投稿画像
            imageString = valueDictionary["image"] as? String
            image = UIImage(data: Data(base64Encoded: imageString!, options: .ignoreUnknownCharacters)!)
            //投稿者の名前
            self.name = valueDictionary["name"] as? String
            //キャプション
            self.caption = valueDictionary["caption"] as? String
            //コメント
            if let comments = valueDictionary["comments"] as? [String] {
                self.comments = comments
            }
            //日付
            let time = valueDictionary["time"] as? String
            self.date = Date(timeIntervalSinceReferenceDate: TimeInterval(time!)!)
            // いいねボタン
            if let likes = valueDictionary["likes"] as? [String] {
                self.likes = likes
            }
            for likeId in self.likes {
                if likeId == myId {
                    self.isLiked = true
                    break
                }
            }
            // いいねボタン2
            if let likes = valueDictionary["likes2"] as? [String] {
                self.likes2 = likes
            }
            for likeId in self.likes2 {
                if likeId == myId {
                    self.isLiked2 = true
                    break
                }
            }
        }
    }
    
```

**コンスト**

```

    import Foundation
    
    struct Const {
        static let PostPath = "posts"
    }
    
```
CC BY-SA 4.0
2020-01-13T16:14:22.990
62217
2020-01-18T01:54:04.597
2020-01-16T15:36:39.187
37426
37426
question
firebase swift5
記事ごとのFirebase孫データの取得ができず、全ての記事で同じコメントが表示されてしまう。
さて、コメントでは少し端折って書いてしまいましたが、あなたが「コメント投稿画面」内のtableViewにコメントの一覧を表示したいのであれば、

  * `tableView(_:numberOfRowsInSection:)`ではコメントの数を返す
  * `tableView(_:cellForRowAt:)`では`indexPath`番目のコメントをセットしたcellを返す

と言うことが必要です。

また「コメント投稿画面」内でタイムライン全体を保持する必要はありません。

そこら辺を踏まえてあなたのコードを書き直すと、こんな感じになります。

(削除すべきところをわかりやすくするために、コメントアウトしているだけの部分がありますが、不要ですのでさっくり削除してください。)

### コメント投稿画面

```

    class ArticleViewController: UIViewController,UITextFieldDelegate, UITableViewDataSource, UITableViewDelegate {
    
        //...
    
        //### この画面で「タイムラインの記事」全部を保持する必要はない
        //var postArray: [PostData] = []
    
        //...
    
        override func viewWillAppear(_ animated: Bool) {
            super.viewWillAppear(animated)
    
            guard let postData = postDataReceived else {
                return
            }
    
            //### この画面でタイムライン全体を監視しても意味が無い。監視するとしたら`postData`だけを監視する
    
            //イメージ画像
            self.articleImage.image = postData.image
            //キャプションのテキスト
            self.articleLabel.text = "\(postData.caption!)"
            //いいねの数
            let likeNumber = postData.likes.count
            articleLilkeCount.text = "\(likeNumber)"
        }
    
        //...
    
        //コメントテーブルビュー
        //### コメントをtableViewに表示するのであれば、ここで「コメントの数」を返さないといけない
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            //`postDataReceived`がnilの時に呼ばれる可能性もあるので、条件付きバインディングで判定
            if let postData = postDataReceived {
                return postData.comments.count  //コメントの数を返す
            } else {
                return 0  //`postDataReceived`がnilなら0
            }
        }
    
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
            // セルを取得してデータを設定する
            //### セルのIDには意味のあるわかりやすい名前をつけましょう
            let cell = tableView.dequeueReusableCell(withIdentifier: "CommentCell", for: indexPath) as! CommentTableViewCell
    
            //### `postDataReceived`がnilの時に呼ばれる可能性もあるので、条件付きバインディングで判定
            guard let postData = postDataReceived else {
                return cell
            }
            //### コメント用セルには、コメントに関する情報を渡さないといけない、記事全体ではない
            //cell.commentSetPostData(postData)
    
            //テキストを初期化
            //### `indexPath`番目のコメントを設定
            cell.commentLabel.text = postData.comments[indexPath.row]
    
            //### セル内のUI要素にアクションを設定する場合、古いアクションをクリアしないといけない
            cell.goodButton.removeTarget(self, action: nil, for: .touchUpInside)
            // セル内のボタンのアクションをソースコードで設定する
            cell.goodButton.addTarget(self, action:#selector(handleGoodButton(_:forEvent:)), for: .touchUpInside)
    
            return cell
        }
    
        //...
    
    
        // セル内のボタンがタップされた時に呼ばれるメソッド
        @objc func handleGoodButton(_ sender: UIButton, forEvent event: UIEvent) {
            print("DEBUG_PRINT: goodボタンがタップされました。")
    
            //### ここでevent.allTouchesから位置を求めても「Goodボタンの位置」が取れるだけ
            // タップされたセルのインデックスを求める
            //let touch = event.allTouches?.first
            //let point = touch!.location(in: self.commentTableView)
            //let indexPath = commentTableView.indexPathForRow(at: point)
    
            //### この画面で表示されている記事のデータを取り出す
            guard let postData = postDataReceived else {
                return
            }
    
            //...
        }
    }
    
```

### カスタムセル

```

    class CommentTableViewCell: UITableViewCell {
    
        @IBOutlet weak var commentLabel: UILabel!
        @IBOutlet weak var goodButton: UIButton!
        @IBOutlet weak var countLabel: UILabel!
    
        //### 不要
        //前画面からデータを受け取るための変数
        //var postDataReceived: PostData?
    
        override func awakeFromNib() {
            super.awakeFromNib()
            // Initialization code
        }
    
        override func setSelected(_ selected: Bool, animated: Bool) {
            super.setSelected(selected, animated: animated)
    
        }
    
        //### `self.commentLabel.text`内容をループ内で次々に入れ替えても意味はない
    //    func commentSetPostData(_ postData: PostData) {
    //        postDataReceived = postData
    //
    //        //postData.commentsの中から要素をひとつずつ取り出すのを繰り返す、というのがcomment
    //        for comment in postData.comments{
    //            //commentLabelに表示するのはcomment
    //            self.commentLabel.text = comment
    //        }
    //    }
    }
    
```

* * *

`Value of optional type 'PostData?' must be unwrapped
...`なんてエラーをご自身で解決できない状態ということは、まだSwift言語の基本中の基本である`Optional`型の扱いが全くわかっていないと言うことになります。

「いろんなサイトの記事をコピペしてつなぎ合わせて、よくわからないままコンパイルだけ通るようにする」なんてことをしているだけでは、どこにでもあるサンプルコード以上のものを作れるようにはなりません。

App Storeにあげられるようなアプリを作りたいのであれば、きちんとSwift言語の基礎から学習し直すことをお勧めします。

* * *

なお、上記のコードは「とりあえずtableViewにコメントを表示する」だけのものです。コードのコメント中に書いた「`postData`だけを監視する」コードはご自身で調べて追加してみてください。
CC BY-SA 4.0
2020-01-18T01:20:07.693
62337
2020-01-18T01:54:04.597
2020-01-18T01:54:04.597
13972
13972
62217
answer