Swift开发:值变更时如何获取下一条数据?
Hey there! Let's tackle your two main issues: fixing the failure to fetch the next question when arrayNum changes, and ditching that repetitive switch code for a cleaner approach.
First: Stop Repeating Code with a Reusable Function
Instead of copying the same Firestore fetch logic across switch cases, wrap it into a single, dynamic function that takes arrayNum as a parameter. This way, you can reuse it anywhere you need to fetch a question, and any updates to the fetch logic only happen in one place.
Here's how to refactor your code:
func fetchQuestion(for arrayIndex: Int) { let roomRef = db.collection("ROOMS_Collection").document(GameData.shared.documentID) roomRef.getDocument { (docSnapshot, error) in // Handle errors first (you were missing this before!) if let error = error { print("Failed to fetch room document: \(error.localizedDescription)") return } guard let docSnapshot = docSnapshot, docSnapshot.exists, let data = docSnapshot.data() else { print("Room document doesn't exist or has no data") return } // Now dynamically get the question based on arrayIndex // Option 1: If your questions are stored in an array field (e.g. "questions") if let questions = data["questions"] as? [String], arrayIndex < questions.count { let currentQuestion = questions[arrayIndex] // Do something with your question (update UI, store in model, etc.) print("Loaded question: \(currentQuestion)") } // Option 2: If questions are in separate fields (e.g. "question1", "question2") else { let questionKey = "question\(arrayIndex)" if let currentQuestion = data[questionKey] as? String { // Handle the question print("Loaded question from key \(questionKey): \(currentQuestion)") } else { print("No question found for index \(arrayIndex)") } } } }
Second: Automatically Fetch When arrayNum Changes
The root issue of not getting the next question when arrayNum changes is that you're not triggering the fetch when the value updates. There are two clean ways to fix this:
Option A: Use Property Observers (Simple, No Frameworks)
If arrayNum is a property in GameData, add a didSet observer to trigger the fetch automatically whenever it changes:
class GameData { static let shared = GameData() var documentID: String = "" var arrayNum: Int = 0 { didSet { // Call our reusable function when the value changes fetchQuestion(for: arrayNum) } } }
Option B: Use Combine for Reactive Updates (Better for SwiftUI/Modern Apps)
If you're using SwiftUI or want a more reactive approach, mark arrayNum as @Published in GameData and subscribe to its changes:
First, update GameData:
import Combine class GameData: ObservableObject { static let shared = GameData() var documentID: String = "" @Published var arrayNum: Int = 0 }
Then, in your ViewModel or view controller, subscribe to the changes:
class QuestionViewModel: ObservableObject { private var cancellables = Set<AnyCancellable>() init() { // Listen for changes to arrayNum and fetch the new question GameData.shared.$arrayNum .sink { [weak self] newIndex in self?.fetchQuestion(for: newIndex) } .store(in: &cancellables) } // Include the fetchQuestion function here or in a shared service func fetchQuestion(for arrayIndex: Int) { // ... the implementation from above } }
Why This Works Better
- No Repetition: All fetch logic lives in one function—no more copying code into switch cases.
- Automatic Triggers: Whenever
arrayNumchanges, the fetch runs automatically, fixing your original issue. - Scalability: If you add more questions later, you don't need to update switch cases—just adjust how you access the data in
fetchQuestion. - Better Error Handling: We added error handling for Firestore calls, which your original code was missing (critical for debugging!).
内容的提问来源于stack exchange,提问作者Tom B.

