【问题标题】:Return array from firestore从firestore返回数组
【发布时间】:2021-03-26 11:02:11
【问题描述】:

swiftui 和 firestore 的新手,在调用此文档数组时遇到了困难。希望有人可以帮助我将“items”数组调用到VStack中。

添加了我一直在尝试的代码

查看模型

import SwiftUI
import FirebaseFirestore

class MovieItemViewModel: ObservableObject {
    
    @Published var movieItems = [MovieItem]()
    
    private var db = Firestore.firestore()
    
    func fetchData() {
        db.collection("movies").order(by: "items").addSnapshotListener { (querySnapshot, error) in
            guard let documents = querySnapshot?.documents else {
                print("No Documents")
                return
            }
            
                self.movieItems = documents.map { (queryDocumentSnapshot) -> MovieItem in
                let data = queryDocumentSnapshot.data()
                
                let items = data["items"] as? String ?? ""
                    
                return MovieItem(item: items)
                
            }
            
        }
    }
}

型号

import SwiftUI

struct MovieItem: Identifiable {
    var id: String = UUID().uuidString
    var item: String
}

主视图

struct MovieDetailListView: View {
    
    @ObservedObject private var viewModel = MovieItemViewModel()

    var body: some View {

     VStack(alignment: .leading, spacing: 15){
        ForEach(viewModel.movieItems.indices, id: \.self) { i in
        Text(viewModel.movieItems[i].item) 
        } 
     }
     .onAppear() { self.viewModel.fetchData() }
}
}

【问题讨论】:

  • 发布您尝试过的代码
  • @Cod3rMax 根据我在网上找到的 YT 视频和答案,我添加了我一直在搞乱的代码。
  • 在当前状态下,在 ForEach 文本上我得到Value of type 'MovieItem' has no member 'name',在视图模型中返回时我得到Argument passed to call that takes no arguments
  • 请检查您的物业名称! 1.你的viewModelMovieItemViewModel没有属性items所以你不能做ForEach(viewModel.items.…。你叫它movieItems,所以ForEach(viewModel.movieItems.…? 2.你的MovieItem没有name的属性,所以你不能做Text(viewModel.items[i].name)
  • @grg 感谢您提出这些意见。我做了一些编辑(我已经编辑了上面的代码)。我不再收到任何错误,但它仍然没有调用任何数据,我在 onAppear 中尝试过print(self.viewModel.fetchData()),但控制台只是打印“()”

标签: swift firebase google-cloud-firestore swiftui


【解决方案1】:

代码中的问题很少。让我先解决 Firebase 问题

这个

.collection("movies").order(by: "items")

不正确,因为 items 不是电影的文档子项。但是590706 是。因此,如果目标是读取 590706 内的项目,则需要指定该路径。

此外,.addSnapshotListener 在该路径上留下一个观察者/侦听器,如果有任何更改,将触发一个事件并将这些更改传递给您的应用程序。看起来你(还)不想要那个 - 看起来你只是想按需读取数据(例如,当用户选择电影时)

以下代码将读取您询问的数据。为简洁起见,我省略了任何错误检查

func readMovieItems() {
    let movieNum = "590706"
    let refToRead = self.db.collection("movies").document(movieNum)
    refToRead.getDocument(completion: { documentSnapshot, error in
        if let err = error {
             print(err.localizedDescription)
             return
         }

        if let doc = documentSnapshot {
            let title = doc.get("movie") as! String
            let items = doc.get("items") as! [String]
            print(title)
            for item in items {
                print(item)
            }
        }
    })
}

从那里,您有很多选择;假设这是一个 Master->Detail 设置,其中包含 master 上的电影列表,当点击电影时,详细信息会显示在详细信息视图中。这样的事情就可以了

struct MasterView: View {
    @Binding var movies: [MovieClass]

    var body: some View {
        List {
            ForEach(movies, id: \.self) { movie in
                NavigationLink(
                    destination: DetailView(selectedMovie: movie)
                ) {
                    Text("\(movie.title)")
                }
            }.onDelete { indices in
                indices.forEach { self.movies.remove(at: $0) }
            }
        }
    }
}

【讨论】:

  • 这正是我要找的!太感谢了!它打印的正是我想要的。现在是一个愚蠢的问题(我很抱歉,我是新手)。我将如何构建视图中的 ForEach 循环以在屏幕上实际显示这些结果?
  • @SeanForReal 对不起 - 走神了。我完成了答案 - 看看。
  • 非常感谢这位杰伊。我已经让主/详细信息设置工作,我只需要知道如何在详细信息页面上显示项目的提要。我不确定您的 MasterView 是否这样做,它似乎更像是母版页,其中列出了带有详细页面链接的电影。在详细信息页面上,您将如何显示项目列表?
  • @SeanForReal 正如您在评论中提到的那样,主人会显示一个“电影列表”,其中包含指向详细页面的链接 - 您的问题实际上是在询问如何阅读和显示列表,这是一个模板。 “项目列表”以完全相同的方式工作 - 将列表传递给 detailView,使其包含在 var @Binding var someItems: [YourItems] 中,并使用相同的代码(显然减去链接)来显示该列表。
  • 非常感谢您的帮助。我明白你的意思,不是 100% 确定该怎么做,但我会努力解决这个问题。我对此很陌生。我已经接受了你的回答,非常感谢!
【解决方案2】:

添加这个扩展:

extension Decodable {
init(fromDictionary: Any) throws {
let data = try JSONSerialization.data(withJSONObject: fromDictionary, options: JSONSerialization.WritingOptions.prettyPrinted)
let decoder = JSONDecoder()
self = try decoder.decode(Self.self, from: data)
      }
}

并确保您的模型符合可解码。

然后简单地调用:

  db.collection("movies").order(by: "items").addSnapshotListener { (querySnapshot, error) in
    if let error = error {
        print(error.localizedDescription)
        return
    }
    guard let snap = snapshot else {
        print("Error getting data")
        return
    }
    var movies = [MoveItem]()
    for document in snap.documents {
        let dict = document.data()
        guard let decodedMovie = try? MovieModel.init(fromDictionary: dict) else {return}
        movies.append(decodedMovie)
    }
}

【讨论】:

    【解决方案3】:

    我想你想让你的 movieItems 属性包含一个电影项目数组,而不是所有文档中所有项目的数组,对吗?如果这不正确,请告诉我,我可以更改答案。

    var movieItems = [[MovieItem]]()
    
    func fetchData() {
        
        db.collection("movies").order(by: "items").addSnapshotListener { snapshot, error in
            if error != nil {
                return
            } else {
                let documents = snapshot!.documents
                
                for eachDoc in documents {
                    let data = eachDoc.data()
                    let items = data["items"] as! [String]
                    let itemArray = generateMovieItemsWith(items: items)
                    self.movieItems.append(itemArray)
                }
            }
        }
        
    }
    
    func generateMovieItemsWith(items: [String]) -> [MovieItem] {
        var movieItems = [MovieItem]()
        for each in items {
            let movieItem = MovieItem(item: each)
            movieItems.append(movieItem)
        }
        return movieItems
    }
    
    struct MovieItem: Identifiable {
        var id: String = UUID().uuidString
        var item: String
        
        init(item: String) {
            self.item = item
        }
    }
    

    【讨论】:

    • 啊,好的,我们很接近了。我明白这是在做什么。它正在收集所有电影的所有“项目”并将它们显示在列表中,所以无论我在看什么电影,它都会显示一个大项目列表。我希望只显示所选电影的项目。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-21
    相关资源
    最近更新 更多