Swift中Firestore评分读写:提交评分功能整合问题
实现星级评分提交并存储到Firestore
我需要实现用户提交星级评分并将其存储在对应文档下的集合中,已经编写了getRatingsSubcollection、addRatingTransaction函数,但不确定如何将这些函数整合到Rating视图结构中,以实现每次用户提交评分时自动运行。
现有代码
struct Rating: View { @State var userCurrentRating: CGFloat = 0.0 var schools = ["North Avenue", "West Village", "Brittain"] @State private var location = "West Village" @State private var isUserRatingCurrent = true @State private var currentRating: CGFloat = 0.0 var db: Firestore! var body: some View { NavigationView{ ScrollView { VStack(spacing: 16) { Divider() Text("Choose a dining location:") .bold() Picker("Choose a dining location:", selection: $location) { ForEach(schools, id: \.self) { Text($0) } } Text("Current Rating, \(currentRating)") .bold() if self.isUserRatingCurrent { VStack { RatingsViewCurrent(onDidRateCurrent: self.userDidRateCurrent, ratingCurrent: self.$userCurrentRating) .frame(width: .infinity, height: 100, alignment: .center) } } else { VStack { RatingsViewCurrent(ratingCurrent: self.$currentRating) .frame(width: .infinity, height: 100, alignment: .center) if userCurrentRating == 0.0 { Button("Rate") { self.isUserRatingCurrent = true } } } } } }.navigationTitle("Add a Rating") } } func userDidRateCurrent(_ ratingCurrent: Int) { print("ratingcurrent \(ratingCurrent)") } struct diningLocation { let location: String let currentRating: Float let usualRating: Float let totalRatings: Float init(location: String, currentRating: Float, usualRating: Float, totalRatings: Float) { self.location = location self.currentRating = currentRating self.usualRating = usualRating self.totalRatings = totalRatings } } let WestVillage = diningLocation(location: "West Village", currentRating: 4.65, usualRating: 2.9, totalRatings: 45.0) struct Rating { let rating: Float } func getRatingsSubcollection() { db.collection("RatingInformation") .document("West Village") .collection("ratings") .getDocuments() { (querySnapshot, err) in // ... } } func addRatingTransaction(restaurantRef: DocumentReference, ratingCurrent: Float) { let ratingRef: DocumentReference = restaurantRef.collection("ratings").document() db.runTransaction({ (transaction, errorPointer) -> Any? in do { let restaurantDocument = try transaction.getDocument(restaurantRef).data() guard var restaurantData = restaurantDocument else { return nil } let totalRatings = restaurantData["totalRatings"] as! Int let newNumRatings = totalRatings + 1 let usualRating = restaurantData["usualRating"] as! Float let oldRatingTotal = usualRating * Float(totalRatings) let newAvgRating = (oldRatingTotal + ratingCurrent) / Float(newNumRatings) restaurantData["totalRatings"] = newNumRatings restaurantData["usualRating"] = newAvgRating transaction.setData(restaurantData, forDocument: restaurantRef) transaction.setData(["rating": ratingCurrent], forDocument: ratingRef) } catch { // Error getting restaurant data // ... } return nil }) { (object, err) in // ... } } }
整合方案
1. 初始化Firestore实例
在Rating视图的初始化方法中完成Firestore的初始化,确保db变量有值:
init() { db = Firestore.firestore() // 可选:配置Firestore持久化等设置 // let settings = FirestoreSettings() // settings.isPersistenceEnabled = true // db.settings = settings }
2. 关联评分提交到用户交互
修改userDidRateCurrent函数,在用户完成评分时触发存储逻辑,并更新本地视图状态:
func userDidRateCurrent(_ ratingCurrent: Int) { print("ratingcurrent \(ratingCurrent)") // 获取当前选中餐厅的Firestore文档引用 let restaurantRef = db.collection("RatingInformation").document(location) // 调用事务存储评分并更新平均评分 addRatingTransaction(restaurantRef: restaurantRef, ratingCurrent: Float(ratingCurrent)) // 更新本地显示的评分值 currentRating = CGFloat(ratingCurrent) userCurrentRating = CGFloat(ratingCurrent) // 切换到已评分状态,展示当前平均评分 isUserRatingCurrent = false }
3. 加载当前餐厅的实时评分
添加函数加载选中餐厅的当前平均评分,并在视图出现和切换餐厅时调用:
func loadCurrentRating() { let restaurantRef = db.collection("RatingInformation").document(location) restaurantRef.getDocument { snapshot, error in guard let data = snapshot?.data(), error == nil else { print("加载评分失败: \(error?.localizedDescription ?? "未知错误")") return } // 更新本地当前评分 if let avgRating = data["usualRating"] as? Float { currentRating = CGFloat(avgRating) } } }
给Picker添加选中变化监听,给ScrollView添加视图出现监听:
Picker("Choose a dining location:", selection: $location) { ForEach(schools, id: \.self) { Text($0) } } .onChange(of: location) { _ in loadCurrentRating() }
ScrollView { // 原有视图内容 } .navigationTitle("Add a Rating") .onAppear { loadCurrentRating() }
4. 完善错误处理
在addRatingTransaction中补充错误处理逻辑,便于调试:
func addRatingTransaction(restaurantRef: DocumentReference, ratingCurrent: Float) { let ratingRef: DocumentReference = restaurantRef.collection("ratings").document() db.runTransaction({ (transaction, errorPointer) -> Any? in do { let restaurantDocument = try transaction.getDocument(restaurantRef).data() guard var restaurantData = restaurantDocument else { print("未找到餐厅文档") return nil } guard let totalRatings = restaurantData["totalRatings"] as? Int, let usualRating = restaurantData["usualRating"] as? Float else { print("餐厅数据格式错误") return nil } let newNumRatings = totalRatings + 1 let oldRatingTotal = usualRating * Float(totalRatings) let newAvgRating = (oldRatingTotal + ratingCurrent) / Float(newNumRatings) restaurantData["totalRatings"] = newNumRatings restaurantData["usualRating"] = newAvgRating transaction.setData(restaurantData, forDocument: restaurantRef) transaction.setData(["rating": ratingCurrent], forDocument: ratingRef) } catch { print("获取餐厅数据出错: \(error.localizedDescription)") } return nil }) { (object, err) in if let err = err { print("事务执行失败: \(err.localizedDescription)") } else { print("评分提交成功") } } }
5. 修复视图逻辑
调整"Rate"按钮的逻辑,支持重新评分:
if userCurrentRating == 0.0 { Button("Rate") { self.isUserRatingCurrent = true } } else { Button("Rate Again") { self.isUserRatingCurrent = true } }
内容的提问来源于stack exchange,提问作者FrancescaD
相关产品推荐
相关产品推荐

