

下記のようなデータ構成でFirestoreにデータが格納してあり、  
下記のような遷移を実現したいです。  
感覚的にはよく使いそうな遷移だと思うのですが、どのように実現するのが良いのか分からず、  
どなたかにご教示いただきたいです。

【データの構成】  
Collection("Theme")→document（）→各documentにCollection("Photo")が含まれる

【実現したいViewの遷移】  
Themeの情報が含まれたView→そのThemeのPhotoが表示されるView

[code]

    //Themeの情報が含まれたView
    import SwiftUI
    
    struct ThemeView: View {
        @ObservedObject var themeList = ThemeObserver()
    
        var body: some View {
            VStack{
                List(themeList.status){ theme in
                    NavigationLink(destination: PhotoView(theme: self.theme)){
                    ThemeView(oneTheme: theme)
                    }
                }
            }
        }
    }
    
    //UserのPhotoが表示されるView
    struct PhotoView: View {
        var theme : ThemeEntity
        var ObservedObject var photoList = PhotoObserver()
        var body: some View {
            photoList.pickup(theme: theme)
    
            return ScrollView{//ScrollViewを外すとなぜか表示されるようになる
                VStack{
                    ForEach(self.status,id: \.self){photo in
                        Text(photo.title)//例
                    }
                }
            }
        }
    }
    
    //FireStoreからThemeを取得するObservableObject
    class ThemeObserver:ObservableObject {
        @Published var status = [ThemeEntity]()
    
            init() {
                let db = Firestore.firestore()
                db.collection("Theme").addSnapshotListener{(snap, error) in
                    if error != nil {
                        print("\(String(describing: error?.localizedDescription))")
                    }
                    for i in snap!.documentChanges {
                            let id = i.document.documentID
                            let themeImageURL = i.document.get("themeImageURL") as? String ?? ""
                            ...
    
                            self.status.append(ThemeEntity(id: id, themeImageURL: themeImageURL, ...))
                    }
                }
            }
        }
    }
    
    
    
    //FIreStoreからfuncでPhotoを取得するObservableObject
    import Foundation
    import FirebaseFirestore
    import SwiftUI
    
    class PhotoObserver: ObservableObject{
        @Published var status = [PhotoEntity]()
    
        func pickup(theme: ThemeEntity) {
            let db = Firestore.firestore()
    
            db.collection("Theme").document("\(oneTheme.id)").collection("Photos").addSnapshotListener{(snap, error) in
                if error != nil {
                    print("\(String(describing: error?.localizedDescription))")
                }
    
                var tempStatus: [PhotoEntity] = []
    
                for i in snap!.documentChanges {
                        let id = i.document.documentID
                        let title = i.document.get("title") as? String ?? ""
                        ....
    
                        tempStatus.append(PhotoEntity(id: id, title: title,...))
                }
                self.status = tempStatus
            }
        }
    }
    
[/code]


CC BY-SA 4.0
2020-05-28T14:47:19.823
67090
2020-05-28T16:51:49.177
2020-05-28T15:14:53.293
19110
39869
question
firebase swiftui
FireStoreのデータを取得しながらViewの遷移をしたい


まず第一に、SwiftUIを使う場合の大前提として、Viewの`body`の定義の中に直接「処理」を書いてはいけません。なんらかの処理をクロージャーとして受け取るイニシャライザやメソッドを呼んで、`photoList.pickup(theme:
theme)`のような「処理」は、そのクロージャーの中に記述します。

今回のように画面遷移時に処理を実行させたいのであれば、[`onAppear`メソッド](https://developer.apple.com/documentation/swiftui/text/3276931-onappear)が適当でしょう。

[code]

    struct PhotoView: View {
        var theme : ThemeEntity
        @ObservedObject var photoList = PhotoObserver()
    
        var body: some View {
            ScrollView {
                VStack {
                    ForEach(self.photoList.status, id: \.self) {photo in
                        Text(photo.title)
                    }
                }
            }.onAppear {
                self.photoList.pickup(theme: self.theme)
            }
        }
    }
    
[/code]

(ご質問中のコードで、`struct PhotoView`の定義中にある、`var ObservedObject var photoList =
...`の部分は、`@ObservedObject var photoList = ...`の間違いではないかと思うのですが?)

* * *

で、Firestoreからのデータの取得をダミーに置き換えてテストしたんですが、残念ながら初期表示がうまくいきませんでした。

どうも`ScrollView`には一部の状態変化があっても画面更新を行わない場合があるらしく、本家英語版のstackoverflowに、似たような状況での回避策がいくつか載っていました。  
[SwiftUI ScrollView not getting
updated?](https://stackoverflow.com/q/58830896/6541007)

どの回避策も、いかにも「回避策」と言ったものなのですが、とりあえずアイデアだけ一番得票の多い回答から拝借して、以下のようなコードを書いたところ、こちらのダミーベースでは表示されるようになりました。

[code]

    struct PhotoView: View {
        var theme : ThemeEntity
        @ObservedObject var photoList = PhotoObserver()
    
        var body: some View {
            ScrollView(showsIndicators: photoList.status.isEmpty) {
                VStack {
                    ForEach(self.photoList.status, id: \.self) {photo in
                        Text(photo.title)
                    }
                }
            }
            .onAppear {
                self.photoList.pickup(theme: self.theme)
            }
        }
    }
    
[/code]

あなたの環境で確実に動くものかどうかなんとも言えませんが、お試しください。


CC BY-SA 4.0
2020-05-28T16:51:49.177
67094
2020-05-28T16:51:49.177
13972
67090
answer