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) }) } } } }
关键修复点
- ViewModel线程安全:通过
@MainActor和DispatchQueue.main.async,确保所有对users数组的修改都在主线程执行,避免后台线程与UI线程的并发冲突。 - View结构修正:将
.searchable修饰符移到正确位置,保证搜索框全局可用;添加.onChange回调统一处理搜索逻辑。 - 语法补全:补全原代码中缺失的闭合括号,避免编译错误。
内容的提问来源于stack exchange,提问作者user21597059
相关产品推荐
相关产品推荐

