SwiftUI+Firebase:数据库用户权限复选框修改及代码优化问题
SwiftUI Firebase用户权限修改与代码简化解决方案
问题1:无法修改用户权限(提示user为let常量)
原因:List遍历出的user是不可变的let常量,且User是值类型struct,直接修改内部属性会报错。此外修改后需要同步更新Firebase数据库,不能仅修改本地数据。
解决步骤:
- 在
AdministratorManager中添加修改权限的方法,通过用户number(文档ID)定位用户,更新本地数组并同步Firebase:
func updatePermission(forUserNumber number: String, atIndex index: Int, newValue: Bool) { guard let userIndex = users.firstIndex(where: { $0.number == number }) else { return } // 更新本地数据 users[userIndex].permessi[index] = newValue // 同步Firebase数据库 DatabaseFirestore.collection("Admins").document(number).updateData([ "Permessi": users[userIndex].permessi ]) { error in if let error = error { print("更新权限失败: \(error.localizedDescription)") } } }
- 在View中调用该方法替代直接修改
user属性:
将原代码中的user.permessi[0].toggle()替换为administratorManager.updatePermission(forUserNumber: user.number, atIndex: 0, newValue: !user.permessi[0])
问题2:ForEach简化代码的错误
原代码语法错误,且无法获取权限索引以修改对应值。需遍历权限数组的索引,同时获取对应Bool值:
修正后的ForEach写法:
ForEach(user.permessi.indices, id: \.self) { index in let isEnabled = user.permessi[index] HStack { Image(systemName: isEnabled ? "checkmark.square.fill" : "square") .foregroundColor(isEnabled ? Color(UIColor.systemBlue) : Color.secondary) .onTapGesture { administratorManager.updatePermission(forUserNumber: user.number, atIndex: index, newValue: !isEnabled) } Text("\(index)") .onTapGesture { administratorManager.updatePermission(forUserNumber: user.number, atIndex: index, newValue: !isEnabled) } .padding(1) } }
说明:通过permessi.indices遍历索引,id: \.self保证元素唯一性,从而拿到对应权限的索引并调用更新方法。
完整修正后的代码
User结构(无需修改,确保Identifiable)
struct User: Identifiable { var id: String = UUID().uuidString var name: String var surname: String var school: String var orari: [String] var permessi: [Bool] var number: String }
AdministratorManager的fetchData与新增updatePermission方法
class AdministratorManager: ObservableObject { @Published var users: [User] = [] func fetchData(collection: String) { DatabaseFirestore.collection(collection).addSnapshotListener { (querySnapshot, error) in guard let documents = querySnapshot?.documents else { print("No documents") return } self.users = documents.map { (queryDocumentSnapshot) -> User in let data = queryDocumentSnapshot.data() let name = data["Nome"] as? String ?? "" let surname = data["Cognome"] as? String ?? "" let school = data["Scuola"] as? String ?? "" let orari = data["Orari"] as? [String] ?? [] let permessi = data["Permessi"] as? [Bool] ?? [] let number = queryDocumentSnapshot.documentID return User(name: name, surname: surname, school: school, orari: orari, permessi: permessi, number: number) } } } func updatePermission(forUserNumber number: String, atIndex index: Int, newValue: Bool) { guard let userIndex = users.firstIndex(where: { $0.number == number }) else { return } users[userIndex].permessi[index] = newValue DatabaseFirestore.collection("Admins").document(number).updateData([ "Permessi": users[userIndex].permessi ]) { error in if let error = error { print("权限更新失败: \(error.localizedDescription)") } } } }
最终View代码
List(administratorManager.users) { user in HStack { VStack(alignment: .leading) { Text(user.number).font(.subheadline) Text(user.name).font(.subheadline) Text(user.surname).font(.subheadline) VStack(alignment: .leading){ Text("Permessi") .font(.title2) .fontWeight(.bold) .padding(1) // 用ForEach简化权限列表 ForEach(user.permessi.indices, id: \.self) { index in let isEnabled = user.permessi[index] HStack{ Image(systemName: isEnabled ? "checkmark.square.fill" : "square") .foregroundColor(isEnabled ? Color(UIColor.systemBlue) : Color.secondary) .onTapGesture { administratorManager.updatePermission(forUserNumber: user.number, atIndex: index, newValue: !isEnabled) } Text("\(index)") .onTapGesture { administratorManager.updatePermission(forUserNumber: user.number, atIndex: index, newValue: !isEnabled) } .padding(1) } } } } } } .onAppear() { administratorManager.fetchData(collection: "Admins") }
内容的提问来源于stack exchange,提问作者mickele29
相关产品推荐
相关产品推荐

