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

Firebase用户搜索点击崩溃:Simultaneous accesses错误解析与修复

错误含义解释

这个错误是Swift的并发数据竞争问题:当应用同时在两个不同线程(比如后台线程修改数据、主线程读取渲染UI)访问同一个可变内存地址(此处为viewModel.users),且至少有一个操作是修改(写入)时,就会触发该错误。Swift要求对可变状态的修改必须是排他性的,不允许读写/写写操作同时进行,否则会导致数据不一致或直接崩溃。

通常这类问题出现在SearchViewModel中——你可能在后台线程从Firebase获取用户数据后,直接修改了users数组,没有切换回主线程,也未用并发安全的方式处理状态更新。

代码修复方案

第一步:修复SearchViewModel的并发安全性

确保所有状态更新都在主线程执行,避免数据竞争:

import Firebase
import Foundation

@MainActor // 强制所有状态更新在主线程执行
class SearchViewModel: ObservableObject {
    @Published var users = [User]()
    
    init() {
        fetchUsers()
    }
    
    // 获取全部用户
    func fetchUsers() {
        Firestore.firestore().collection("users").getDocuments { snapshot, error in
            guard let documents = snapshot?.documents else { return }
            // 切换主线程更新UI状态
            DispatchQueue.main.async {
                self.users = documents.compactMap { try? $0.data(as: User.self) }
            }
        }
    }
    
    // 根据搜索文本过滤用户
    func filterUsers(with searchText: String) {
        guard !searchText.isEmpty else {
            fetchUsers()
            return
        }
        
        Firestore.firestore().collection("users")
            .whereField("username", isGreaterThanOrEqualTo: searchText)
            .whereField("username", isLessThanOrEqualTo: "\(searchText)\u{f8ff}")
            .getDocuments { snapshot, error in
                guard let documents = snapshot?.documents else { return }
                // 必须在主线程更新@Published变量
                DispatchQueue.main.async {
                    self.users = documents.compactMap { try? $0.data(as: User.self) }
                }
            }
    }
}

第二步:修复View的结构与逻辑

调整View的修饰符位置,绑定搜索逻辑并补全语法:

struct SearchView: View {
    @State private var searchText = ""
    @StateObject var viewModel = SearchViewModel()
    
    var body: some View {
        NavigationStack{
            ScrollView{
                LazyVStack(spacing: 12){
                    ForEach(viewModel.users) { user in
                        NavigationLink(value: user) {
                            HStack{
                                Image("Logo")
                                    .resizable()
                                    .scaledToFill()
                                    .frame(width: 40, height: 40)
                                    .clipShape(Circle())
                                VStack(alignment: .leading){
                                    Text(user.username)
                                        .fontWeight(.semibold)
                                }
                                Spacer()
                            }
                            .padding(.horizontal)
                        }
                    }
                    .padding(.top, 8)
                }
                // 将searchable移到LazyVStack外部,确保全局生效
                .searchable(text: $searchText, prompt: "Search...")
                // 搜索文本变化时触发ViewModel的过滤逻辑
                .onChange(of: searchText) { newValue in
                    viewModel.filterUsers(with: newValue)
                }
                .navigationDestination(for: User.self, destination: { user in
                    ProfileView(user: user)
                })
            }
        }
    }
}
关键修复点
  1. ViewModel线程安全:通过@MainActor和DispatchQueue.main.async,确保所有对users数组的修改都在主线程执行,避免后台线程与UI线程的并发冲突。
  2. View结构修正:将.searchable修饰符移到正确位置,保证搜索框全局可用;添加.onChange回调统一处理搜索逻辑。
  3. 语法补全:补全原代码中缺失的闭合括号,避免编译错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 04:17:12