🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Firebase

Firebaseは、Googleが提供するBasSサービスの一つ。リアルタイム通知可能、並びにアクセス制御ができるオブジェクトデータベース機能を備えます。さらに認証機能、アプリケーションのログ解析機能などの利用も可能です。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

1回答

1443閲覧

タイムライン画面から詳細画面へのデータの反映(Firebase)ができません

iOS25535009

総合スコア12

Firebase

Firebaseは、Googleが提供するBasSサービスの一つ。リアルタイム通知可能、並びにアクセス制御ができるオブジェクトデータベース機能を備えます。さらに認証機能、アプリケーションのログ解析機能などの利用も可能です。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2019/12/30 15:50

前提・実現したいこと

Xcode11.3
Swift5
macOSMojave10.14.6

フェイスブックのコメントボタンを押した時のような、タイムライン画面から個別の画面に遷移し、タイムラインで表示されていた画像やテキストなどが遷移先でも表示されるようにしたい

タイムライン画面ではUItableViewを使い、それぞれのセルはxibファイルを使い、データベースはFirebaseを使ってます。
遷移先にはUIView,UIButton,UILabelがあります。

発生している問題・エラーメッセージ

遷移先で画像やテキストが反映されない
didSelectRowAtでタップされたセル番号が判別されているようですが、その判別されたセル番号のデータを取得し、表示させることができません。

該当のソースコード

遷移元

Swift

1import UIKit 2import Firebase 3 4class HomeViewController: UIViewController, UITableViewDataSource, UITableViewDelegate { 5 6 @IBOutlet weak var tableView: UITableView! 7 8 var postArray: [PostData] = [] 9 10 // DatabaseのobserveEventの登録状態を表す 11 var observing = false 12 13 override func viewDidLoad() { 14 super.viewDidLoad() 15 16 tableView.delegate = self 17 tableView.dataSource = self 18 19 let nib = UINib(nibName: "PostTableViewCell", bundle: nil) 20 tableView.register(nib, forCellReuseIdentifier: "Cell") 21 22 // テーブル行の高さをAutoLayoutで自動調整する 23 tableView.rowHeight = UITableView.automaticDimension 24 // テーブル行の高さの概算値を設定しておく 25 // 高さ概算値 = 「縦横比1:1のUIImageViewの高さ(=画面幅)」+「いいねボタン、キャプションラベル、その他余白の高さの合計概算(=100pt)」 26 tableView.estimatedRowHeight = UIScreen.main.bounds.width + 100 27 } 28 29 override func viewWillAppear(_ animated: Bool) { 30 super.viewWillAppear(animated) 31 print("DEBUG_PRINT: viewWillAppear") 32 33 if Auth.auth().currentUser != nil { 34 if self.observing == false { 35 // 要素が追加されたらpostArrayに追加してTableViewを再表示する 36 let postsRef = Database.database().reference().child(Const.PostPath) 37 postsRef.observe(.childAdded, with: { snapshot in 38 print("DEBUG_PRINT: .childAddedイベントが発生しました。") 39 40 // PostDataクラスを生成して受け取ったデータを設定する 41 if let uid = Auth.auth().currentUser?.uid { 42 let postData = PostData(snapshot: snapshot, myId: uid) 43 self.postArray.insert(postData, at: 0) 44 45 // TableViewを再表示する 46 self.tableView.reloadData() 47 } 48 }) 49 // 要素が変更されたら該当のデータをpostArrayから一度削除した後に新しいデータを追加してTableViewを再表示する 50 postsRef.observe(.childChanged, with: { snapshot in 51 print("DEBUG_PRINT: .childChangedイベントが発生しました。") 52 53 if let uid = Auth.auth().currentUser?.uid { 54 // PostDataクラスを生成して受け取ったデータを設定する 55 let postData = PostData(snapshot: snapshot, myId: uid) 56 57 // 保持している配列からidが同じものを探す 58 var index: Int = 0 59 for post in self.postArray { 60 if post.id == postData.id { 61 index = self.postArray.firstIndex(of: post)! 62 break 63 } 64 } 65 66 // 差し替えるため一度削除する 67 self.postArray.remove(at: index) 68 69 // 削除したところに更新済みのデータを追加する 70 self.postArray.insert(postData, at: index) 71 72 // TableViewを再表示する 73 self.tableView.reloadData() 74 } 75 }) 76 77 // DatabaseのobserveEventが上記コードにより登録されたため 78 // trueとする 79 observing = true 80 } 81 } else { 82 if observing == true { 83 // ログアウトを検出したら、一旦テーブルをクリアしてオブザーバーを削除する。 84 // テーブルをクリアする 85 postArray = [] 86 tableView.reloadData() 87 // オブザーバーを削除する 88 let postsRef = Database.database().reference().child(Const.PostPath) 89 postsRef.removeAllObservers() 90 91 // DatabaseのobserveEventが上記コードにより解除されたため 92 // falseとする 93 observing = false 94 } 95 } 96 } 97 98 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 99 return postArray.count 100 } 101 102 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 103 // セルを取得してデータを設定する 104 let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! PostTableViewCell 105 cell.setPostData(postArray[indexPath.row]) 106 107 // セル内のボタンのアクションをソースコードで設定する 108 cell.likeButton.addTarget(self, action:#selector(handleButton(_:forEvent:)), for: .touchUpInside) 109 110 return cell 111 } 112 //セルをタップしたら... 113 func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 114 115 // タップされたセルの行番号を出力 116 print("(indexPath.row)番目の行が選択されました。") 117 //セルの選択を解除 118 tableView.deselectRow(at: indexPath, animated: true) 119 //記事画面へ遷移 120 performSegue(withIdentifier: "Article", sender: nil) 121 } 122 123 // セル内のボタンがタップされた時に呼ばれるメソッド 124 @objc func handleButton(_ sender: UIButton, forEvent event: UIEvent) { 125 print("DEBUG_PRINT: likeボタンがタップされました。") 126 127 // タップされたセルのインデックスを求める 128 let touch = event.allTouches?.first 129 let point = touch!.location(in: self.tableView) 130 let indexPath = tableView.indexPathForRow(at: point) 131 132 // 配列からタップされたインデックスのデータを取り出す 133 let postData = postArray[indexPath!.row] 134 135 // Firebaseに保存するデータの準備 136 if let uid = Auth.auth().currentUser?.uid { 137 if postData.isLiked { 138 // すでにいいねをしていた場合はいいねを解除するためIDを取り除く 139 var index = -1 140 for likeId in postData.likes { 141 if likeId == uid { 142 // 削除するためにインデックスを保持しておく 143 index = postData.likes.firstIndex(of: likeId)! 144 break 145 } 146 } 147 postData.likes.remove(at: index) 148 } else { 149 postData.likes.append(uid) 150 } 151 152 // 増えたlikesをFirebaseに保存する 153 let postRef = Database.database().reference().child(Const.PostPath).child(postData.id!) 154 let likes = ["likes": postData.likes] 155 postRef.updateChildValues(likes) 156 157 } 158 } 159} 160

遷移先

Swift

1import UIKit 2import Firebase 3import SVProgressHUD 4 5class ArticleViewController: UIViewController,UITextFieldDelegate { 6 7 @IBOutlet weak var ArticleImage: UIImageView! 8 @IBOutlet weak var ArticleLabel: UILabel! 9 @IBOutlet weak var ArticleButton: UIButton! 10 @IBOutlet weak var ArticleLilkeCount: UILabel! 11 @IBOutlet weak var CommentLabel: UILabel! 12 @IBOutlet weak var CommentTextField: UITextField! 13 14 15 override func viewDidLoad() { 16 super.viewDidLoad() 17 self.CommentTextField.delegate = self 18 CommentTextField.returnKeyType = .done 19 20 21 } 22 23 func setPostData(_ postData: PostData) { 24 //イメージ画像 25 self.ArticleImage.image = postData.image 26 //キャプションのテキスト 27 self.ArticleLabel.text = "(postData.name!) : (postData.caption!)" 28 //いいねの数 29 let likeNumber = postData.likes.count 30 ArticleLilkeCount.text = "(likeNumber)" 31// //日付 32// let formatter = DateFormatter() 33// formatter.dateFormat = "yyyy-MM-dd HH:mm" 34// let dateString = formatter.string(from: postData.date!) 35// self.dateLabel.text = dateString 36 //いいねボタン 37 if postData.isLiked { 38 let buttonImage = UIImage(named: "like_exist") 39 self.ArticleButton.setImage(buttonImage, for: .normal) 40 } else { 41 let buttonImage = UIImage(named: "like_none") 42 self.ArticleButton.setImage(buttonImage, for: .normal) 43 } 44 45 } 46 47 48 //キーボードを閉じる 49 @IBAction func textField(_ sender: Any) { 50 CommentTextField.text = (sender as AnyObject).text 51 } 52 //コメント投稿ボタン 53 @IBAction func CommentButton(_ sender: UIButton) { 54 55 } 56} 57

試したこと

様々なネット上のやり方を試しましたが、うまくいきせん。(そもそもネット上で見つけられませんでした)

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

タップされたCellのindexPathをキーにして、タップされたCellに該当するデータを抽出し、それを画面遷移する際に、遷移先に渡して、遷移先で表示してみてください。

データの取得はcellForRowAtのなかでindexPathをキーにしてcellにデータを渡している部分を参考にしてください。

遷移&値渡しは↓な感じで

swiftにおける値渡しの方法の一部をご紹介

-- 追記 --

・渡すデータの取得
let postData = postArray[indexPath.row]

・渡し方、
ArticleViewControllerのfunc setPostData(_ postData: PostData)を利用するのかと思うのですが、遷移先のVC(avc)を生成した時点ではavc.setPostData(postData)できないと思うので、動かなかったら、しょうがないので、presentのcompletionで渡してあげてみてください。

遷移先での表示についてなので、遷移先で編集したデータの保存については別途考えてください。

-- 追記 --

画面遷移ができているという前提で、

swuft

1let postData = postArray[indexPah.row] 2 3let nextVC 4 = self.storyboard? 5 .instantiateViewController(withIdentifier: "Article") as! ArticleViewController 6 7self.present(nextVC, animated: true, completion: { 8 nextVC.setPostData(postData) 9}) 10

これでうごくんじゃないかな?

なんでcompletionで渡してるかは、遷移先にsetPost(_:)があり、postDataを受ける変数がないから。
nilになるとかは、viewControllerのライフサイルとかで調べてみてください。

投稿2019/12/30 20:51

編集2020/01/06 16:33
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

iOS25535009

2019/12/31 00:12

遷移先でのindexPathの使い方がわかりません。
iOS25535009

2020/01/05 15:49

このように書いてタップしてもピクリともしません。 ``` func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath,_ postData: PostData) { // タップされたセルの行番号を出力 print("(indexPath.row)番目の行が選択されました。") //記事画面へ遷移 let nextVC = self.storyboard?.instantiateViewController(withIdentifier: "Article") as! ArticleViewController //イメージ画像 nextVC.ArticleImage.image = postData.image //キャプションのテキスト nextVC.ArticleLabel.text = "(postData.name!) : (postData.caption!)" //いいねの数 let likeNumber = postData.likes.count nextVC.ArticleLilkeCount.text = "(likeNumber)" //いいねボタン if postData.isLiked { let buttonImage = UIImage(named: "like_exist") nextVC.ArticleButton.setImage(buttonImage, for: .normal) } else { let buttonImage = UIImage(named: "like_none") nextVC.ArticleButton.setImage(buttonImage, for: .normal) } self.navigationController?.popViewController(animated: true) //セルの選択を解除 tableView.deselectRow(at: indexPath, animated: true) } ``` self.present(nextVC, animated: true, completion: nil)をつけても同様です。 ご教授願います。
退会済みユーザー

退会済みユーザー

2020/01/06 04:27

質問文では、Sequeで遷移してたとおもいますが?今度はナビゲーションバー? 何がピクリとも動かないのかわかりませんが、もしかして、できないのは、値を渡すことでは無く画面遷移ではないですか?
iOS25535009

2020/01/06 11:05

失礼しました。色々いじってごちゃつきました。 セグエでいきます。 下記のように書いていますが、 func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { // タップされたセルの行番号を出力 print("(indexPath.row)番目の行が選択されました。") let postData = postArray[indexPath.row] //記事画面へ遷移 let nextVC = self.storyboard?.instantiateViewController(withIdentifier: "Article") as! ArticleViewController //イメージ画像 nextVC.ArticleImage.image = postData.image //キャプションのテキスト nextVC.ArticleLabel.text = "(postData.name!) : (postData.caption!)" //いいねの数 let likeNumber = postData.likes.count nextVC.ArticleLilkeCount.text = "(likeNumber)" //いいねボタン if postData.isLiked { let buttonImage = UIImage(named: "like_exist") nextVC.ArticleButton.setImage(buttonImage, for: .normal) } else { let buttonImage = UIImage(named: "like_none") nextVC.ArticleButton.setImage(buttonImage, for: .normal) } self.present(nextVC, animated: true, completion: nil) //セルの選択を解除 tableView.deselectRow(at: indexPath, animated: true) } タップすると、Thread 1: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional valueというnilを検知されました。 このエラーのため先に進めません。どの部分がそうさせるのでしょうか?
退会済みユーザー

退会済みユーザー

2020/01/06 13:20 編集

画面遷移は実現できているのでしょうか? 画面遷移ができるかわからない場合は、値渡しのコードをコメントアウトして、遷移先を表示できるか試してください。 遷移ができないなら、コード全体とStoryboardを載せてください。 画面遷移ができているなら、回答を読んで書いてあることを試してみてください。
iOS25535009

2020/01/06 13:49

ありがとうございます。コメントアウトで画面遷移はなります。 一通り試しましたが、全てダメでした。 ちなみに「completionで渡す」とはどういうことでしょうか? ご教授願います。
退会済みユーザー

退会済みユーザー

2020/01/06 16:33

> 一通り試しましたが、全てダメでした。 そう書かれても、申し訳ないんですが、何が一通りで、何が全てダメだかわかりません。
iOS25535009

2020/01/07 09:44

completion: {nextVC.setPostData(postData)}で表示できました。ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問