質問をすることでしか得られない、回答やアドバイスがある。

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

新規登録して質問してみよう
ただいま回答率
85.48%
Cloud Firestore

Cloud Firestore は、自動スケーリングと高性能を実現し、アプリケーション開発を簡素化するように構築された NoSQLドキュメントデータベースです。

iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Swift

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

Q&A

0回答

1442閲覧

Firestoreから取得したデータを、CollectionViewに反映する時にエラーになる

yoheionishi

総合スコア5

Cloud Firestore

Cloud Firestore は、自動スケーリングと高性能を実現し、アプリケーション開発を簡素化するように構築された NoSQLドキュメントデータベースです。

iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Swift

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

0グッド

0クリップ

投稿2020/03/21 14:23

編集2020/03/21 14:31

前提・実現したいこと

コレクションビューのセルに、firestoreに格納しているセル名を表示したいです。

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

エラーメッセージ Thread 1: Fatal error: Index out of range

上記のエラーメッセージが発生。
(通常、配列に入れる要素の数等がおかしい場合に出るエラーとのことです)

firestore上のドキュメントからクエリで(サブコレクションの)フィールド情報を取得して配列(mtIds)に格納。
同じように、セル名に該当する情報も配列(namedata)に格納。

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell

上記のセルの設定で、「namedata」配列を使ってセル名を入力しようとするとエラーが発生してしまいます。

該当のソースコード

Swift

1 2 3class SecondViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout { 4 5 @IBOutlet weak var collectionView: UICollectionView! 6 7 private var namedata: [String] = [] 8 private var mtIds: [Int] = [] 9 10 var selectedmtd = Int() 11 12 override func viewDidLoad() { 13 super.viewDidLoad() 14 15 self.loadData() 16 17 // レイアウトを調整 18 collectionView.contentInset = UIEdgeInsets(top: 12, left: 24, bottom: 16, right: 24) 19 20 let layout = UICollectionViewFlowLayout() 21 layout.minimumInteritemSpacing = 8 22 collectionView.collectionViewLayout = layout 23 24 } 25 26 27 // MARK: UICollectionViewDataSource 28 func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 29 return mtIds.count // 表示するセルの数 30 } 31 32 33 // MARK: UICollectionViewDataSource 34 func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 35 let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) // 表示するセルを登録(先程命名した"Cell") 36 cell.backgroundColor = .white // セルの色 37 38 let bgimage = cell.contentView.viewWithTag(2) as! UIImageView 39 bgimage.image = UIImage(named: "nobadge") 40 41 let celllabel = cell.contentView.viewWithTag(1) as! UILabel 42 celllabel.text = namedata[indexPath.row] 43 44 return cell 45 } 46 47 // MARK: UICollectionViewDelegateFlowLayout 48 49 func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { 50 return CGSize(width: cellWidth, height: 120) 51 } 52 53 private var cellWidth: CGFloat { 54 let availableWidth = collectionView.bounds.inset(by: collectionView.adjustedContentInset).width 55 let interColumnSpace = CGFloat(20) 56 let numColumns = CGFloat(4) 57 let numInterColumnSpaces = numColumns - 1 58 59 return ((availableWidth - interColumnSpace * numInterColumnSpaces) / numColumns).rounded(.down) 60 } 61 62 63 private func loadData() { 64 65 let db = Firestore.firestore() 66 67 let user = Auth.auth().currentUser 68 69 db.collection("users").document(user!.uid).collection("history").getDocuments() { (querySnapshot, err) in 70 if let err = err { 71 // エラー時の処理 72 print("Error getting documents: (err)") 73 return 74 } 75 self.mtIds = querySnapshot!.documents.compactMap { $0.data()["historyid"] as? Int } 76 77 78 //---------------------------- 79 for id in self.mtIds { 80 db.collection("mtinfo").whereField("mtid", isEqualTo: id).getDocuments() { (querySnapshot, err) in 81 if let err = err { 82 print("[loadData] Error getting documents: (err)") 83 } else { 84 for document in querySnapshot!.documents { 85 self.namedata.append(document.data()["name"] as! String) 86 } 87 } 88 } 89 } 90 //---------------------------- 91 92 // コレクションビューを更新 93 self.collectionView.reloadData() 94 95 } 96 97 } 98 99} 100 101 102 103

試したこと

「namedata」へのデータ格納が終わる前に、エラー発生しているように見えるので、エラーが発生しているであろう部分をコメントアウトすると、エラーが発生せず、かつ「namedata」配列に正しくデータが格納されます。

 celllabel.text = namedata[indexPath.row]

loadData() の位置をviewdidload()の最初の方に持ってきたりしましたが、あまり意味はなく・・

処理順の問題なのか、もっと単純なミスなのか、どうしても原因が分からないのでご教授いただけると本当に助かります。

どうぞよろしくお願いいたします。

補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

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

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

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

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

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

hoshi-takanori

2020/03/21 16:35

Firestore の getDocuments の結果は非同期なので、reloadData の時点では namedata はまだ空ですし、mtIds の順番通りになる保証もありません。
yoheionishi

2020/03/22 04:38

ありがとうございます! Firestoreのgetも含めて処理が非同期のため、空のnamedataを書き込んでエラーになっていたのですね。 プログラミング初めて間も無く、非同期処理という考え方自体をよく知らず、ご指摘いただいて助かりました! Swiftの場合クロージャを使うことが第一歩のようなので、ググりながら方法を探ってみます。 ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問