You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI传递正确GroupT却获取错误Carpool ID的问题排查

问题描述

开发SwiftUI应用时,为特定拼车组(GroupT)获取事件数据时遇到问题:CalendarCell视图始终获取默认组的事件,即便传入了含正确Carpool ID的GroupT对象。

预期行为:选择拼车组后,CalendarCell应使用该组的Carpool ID拉取事件,但EventViewModel中使用的ID始终是最新创建组的ID,目前通过UserDefaults获取Carpool ID。

CalendarCell视图代码

struct CalendarCell: View {
    let group: GroupT
    @StateObject var eventViewModel: EventViewModel
    @State private var events: [Event] = []
    @State private var isShowingDailyEventPage = false

    init(group: GroupT) {
        self.group = group
        _eventViewModel = StateObject(wrappedValue: EventViewModel(group: group))  // 用所选组初始化EventViewModel
    }

    var body: some View {
        Text("Some Day")
            .onTapGesture {
                fetchDailyEvents()
            }
    }

   func fetchDailyEvents() {
        guard let carpoolIDString = UserDefaults.standard.string(forKey: "carpoolID") else {
            print("Carpool ID not found in UserDefaults")
            return
        }
        let joinCode = group.joinCode
        printCarpoolID()
        print("Retrieved Carpool ID from UserDefaults: \(carpoolIDString)")

        guard let carpoolID = UUID(uuidString: carpoolIDString) else {
            print("Invalid UUID string for Carpool ID: \(carpoolIDString)")
            return
        }

        print("Valid Carpool ID: \(carpoolID.uuidString)")

        let viewModel = EventViewModel(group: GroupT(carpoolID: carpoolID, carpoolName: "Example", admin: "admin", date_created: Date(), members: [], events: [], joinCode: joinCode))
        
        viewModel.fetchDailyEvents(forCarpoolID: carpoolID.uuidString, date: dateForCell()) { result in
            switch result {
            case .success(let events):
                DispatchQueue.main.async {
                    self.events = events
                }
            case .failure(let error):
                print("Error fetching events: \(error)")
            }
        }
    }
}

EventViewModel方法代码

func fetchDailyEvents(forCarpoolID carpoolID: String, date: Date, completion: @escaping (Result<[Event], Error>) -> Void) {
        // DateFormatter for the date string in ISO 8601 format
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "yyyy-MM-dd" // API expects this date format
        let dateString = dateFormatter.string(from: date)

        // Lowercase carpoolID for consistency
        let lowercasedCarpoolID = carpoolID.lowercased()

        // Debugging: Print carpool ID and formatted date
        print("Fetching events for Carpool ID: \(lowercasedCarpoolID) on Date: \(dateString)")

        // Construct the API URL
        guard let apiURL = URL(string: "http://localhost/api/events/\(lowercasedCarpoolID)/date/\(dateString)") else {
            print("Invalid API URL")
            completion(.failure(NetworkError.invalidRequest))
            return
        }

        // Debugging: Print the constructed API URL
        print("Constructed API URL: \(apiURL)")

        // Create URLRequest
        var request = URLRequest(url: apiURL)
        request.httpMethod = "GET"
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")

        // Perform the network request
        let task = URLSession.shared.dataTask(with: request) { data, response, error in
            // Handle potential errors
            if let error = error {
                print("Network error: \(error.localizedDescription)")
                completion(.failure(NetworkError.invalidResponse))
                return
            }

            // Print the HTTP response status code
            if let httpResponse = response as? HTTPURLResponse {
                print("HTTP Response Status Code: \(httpResponse.statusCode)")
            }

            // Ensure data is not nil
            guard let data = data else {
                print("No data received")
                completion(.failure(NetworkError.invalidResponse))
                return
            }

            // Debugging: Print the raw JSON response
            if let jsonString = String(data: data, encoding: .utf8) {
                print("Received JSON: \(jsonString)")
            }

            do {
                // Decode the response as an array of Event
                let decoder = JSONDecoder()
                decoder.dateDecodingStrategy = .iso8601 // API uses ISO 8601 for date and time

                // Attempt decoding
                let events = try decoder.decode([Event].self, from: data)

                // Debugging: Print the decoded events
                print("Successfully decoded events: \(events)")
                completion(.success(events))
            } catch {
                // Print detailed decoding error information
                print("Decoding error: \(error.localizedDescription)")
                completion(.failure(error))
            }
        }
        task.resume()
    }

GroupT结构体代码

struct GroupT: Codable {
    let carpoolID: UUID
    let carpoolName: String
    let admin: String
    var members: [String]
    let date_created: Date
    let events: [Event]
    let joinCode: String
}

已尝试步骤

  • 确认传入CalendarCell的group为正确所选组;
  • 在fetchDailyEvents中打印Carpool ID,确认其正确性;
  • 视图仍使用最新创建组的错误ID拉取事件;
  • 确认Carpool ID已正确保存到UserDefaults,但获取异常。

解决方案

问题根源

  1. 错误依赖UserDefaults:fetchDailyEvents中从UserDefaults取的Carpool ID未随组选择更新,或始终存储最新创建组的ID,导致用错ID;
  2. 重复创建ViewModel:初始化CalendarCell时已用传入的group创建@StateObject的eventViewModel,但fetchDailyEvents里又新建临时实例,完全未复用正确的ViewModel;
  3. 硬编码GroupT实例:新建临时ViewModel时手动构造GroupT,用的是UserDefaults的ID而非传入组的真实数据。

修复步骤

  1. 直接使用传入组的Carpool ID:删除UserDefaults相关逻辑,直接用group.carpoolID,这是当前选中组的正确ID;
  2. 复用已有的EventViewModel:不要新建临时实例,直接用初始化好的eventViewModel调用方法;
  3. 清理冗余代码:删掉手动构造GroupT的无效代码。

修改后的fetchDailyEvents代码:

func fetchDailyEvents() {
    let carpoolID = group.carpoolID.uuidString
    print("Using Carpool ID from selected group: \(carpoolID)")

    eventViewModel.fetchDailyEvents(forCarpoolID: carpoolID, date: dateForCell()) { result in
        switch result {
        case .success(let events):
            DispatchQueue.main.async {
                self.events = events
            }
        case .failure(let error):
            print("Error fetching events: \(error)")
        }
    }
}

额外建议

  • 若需用UserDefaults存储当前选中组ID,必须在用户切换组时立即更新该值;但更可靠的方式是直接通过视图传递的group对象获取ID,避免依赖全局状态;
  • 检查EventViewModel初始化逻辑,确保正确接收并保存传入的group信息,方便后续使用组的其他数据。

内容的提问来源于stack exchange,提问作者Nick

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 00:24:51