如何解决如何将其他用户数据保存到Cloud Firestore?
我成功将其他firstName
,lastName
,email
和gender
保存到Cloud Firestore上的集合中。
我现在希望能够在我的应用程序的设置屏幕中使用和更改此数据。例如:如果用户想更改电子邮件。问题是该电子邮件保存在Firebase Auth中,但也保存在Cloud Firestore的profiles
集合中。您可以同时更改两者吗?
这是我的SessionStore:
import Foundation
import Combine
import Firebase
class SessionStore: ObservableObject {
@Published var profile: UserProfile?
var didChange = PassthroughSubject<SessionStore,Never>()
@Published var session: User? {didSet{self.didChange.send(self) }}
var handle: AuthStateDidchangelistenerHandle?
func listen() {
handle = Auth.auth().addStateDidchangelistener({ (auth,user) in
if let user = user {
self.session = User(uid: user.uid,email: user.email)
}
else {
self.session = nil
}
})
}
private var profileRepository = UserProfileRepository()
func signUp(email: String,password: String,firstName: String,lastName: String,gender:
String,completion: @escaping (_ profile: UserProfile?,_ error: Error?) -> Void) {
Auth.auth().createuser(withEmail: email,password: password) { (result,error) in
if let error = error {
print("Error signing up: \(error)")
completion(nil,error)
return
}
guard let user = result?.user else { return }
print("User \(user.uid) signed up.")
let userProfile = UserProfile(uid: user.uid,email: user.email ?? "",firstName: firstName,lastName: lastName,gender: gender)
self.profileRepository.createProfile(profile: userProfile) { (profile,error) in
if let error = error {
print("Error while fetching the user profile: \(error)")
completion(nil,error)
return
}
self.profile = profile
completion(profile,nil)
}
}
}
func signIn(email: String,_ error: Error?) -> Void) {
Auth.auth().signIn(withEmail: email,error) in
if let error = error {
print("Error signing in: \(error)")
completion(nil,error)
return
}
guard let user = result?.user else { return }
print("User \(user.uid) signed in.")
self.profileRepository.fetchProfile(userId: user.uid) { (profile,error)
return
}
self.profile = profile
completion(profile,nil)
}
}
}
func signOut() {
do {
try Auth.auth().signOut()
self.session = nil
self.profile = nil
}
catch let signOutError as NSError {
print("Error signing out: \(signOutError)")
}
}
func unbind() {
if let handle = handle {
Auth.auth().removeStateDidchangelistener(handle)
}
}
deinit {
unbind()
}
struct User {
var uid: String
var email: String?
init(uid: String,email: String?) {
self.uid = uid
self.email = email
}
}
}
我的个人资料存储库:
import Foundation
import Combine
import Firebase
import FirebaseFirestoreSwift
struct UserProfile: Codable {
var uid: String
var email: String
var firstName: String
var lastName: String
var gender: String
}
class UserProfileRepository: ObservableObject {
private var db = Firestore.firestore()
func createProfile(profile: UserProfile,_
error: Error?) -> Void) {
do {
let _ = try db.collection("profiles").document(profile.uid).setData(from: profile)
completion(profile,nil)
}
catch let error {
print("Error writing to Firestore: \(error)")
completion(nil,error)
}
}
func fetchProfile(userId: String,_ error:
Error?) -> Void) {
db.collection("profiles").document(userId).getDocument { (snapshot,error) in
let profile = try? snapshot?.data(as: UserProfile.self)
completion(profile,error)
}
}
}
和设置视图:
import SwiftUI
import FirebaseAuth
import Firebase
struct SettingsView: View {
@State var showEdit = false
var genderOptions = ["Male","Female","Other"]
@StateObject var viewmodel = UserProfileRepository()
@State var firstName: String = ""
@State var lastNameName: String = ""
@State var email: String = ""
@State var gender: String = ""
var body: some View {
ScrollView {
vstack {
HStack {
Text("Settings")
}
.padding()
vstack {
Spacer()
HStack {
Image(systemName: "person.fill")
if showEdit == true {
TextField("First Name",text: $firstName)
.autocapitalization(.words)
.keyboardType(.default)
.font(.subheadline)
}
else {
Text("")
.font(.subheadline)
.padding()
.onTapGesture {
showEdit = true
}
}
}
HStack {
Image(systemName: "envelope.fill")
if showEdit == true {
TextField("Email",text: $email)
.autocapitalization(.none)
.keyboardType(.emailAddress)
.font(.subheadline)
}
else {
Text("")
.font(.subheadline)
.padding()
.onTapGesture {
showEdit = true
}
}
HStack {
Image(systemName: "figure.wave")
if showEdit == true {
Picker(selection: $gender,label: Text("")) {
ForEach(genderOptions,id: \.self) {
Text($0)
.font(.footnote)
}
}
.pickerStyle(SegmentedPickerStyle())
.frame(maxWidth: .infinity)
.padding()
}
else {
Text("")
.font(.subheadline)
.padding()
.onTapGesture {
showEdit = true
}
}
Spacer()
}
}
if showEdit == true {
Image(systemName: "checkmark")
.onTapGesture{
showEdit.toggle()
}
}
}
.onAppear {
}
}
}
}
struct SettingsView_Previews: PreviewProvider {
static var previews: some View {
SettingsView()
}
}
解决方法
一些注意事项:
- 无需在您的
didChange = PassthroughSubject
上实现SessionStore
-一旦您更改了任何@Published
属性,就会通知所有订阅者。 - 无需实现自己的
User
结构-只需使用从Firebase Auth获得的结构即可-它具有您需要照顾的所有属性。 - 在 Settings 视图中,尝试将整个视图包装在
NavigationView
中,将navigationBarTitle
设置为Settings
-这应该为您提供典型的设置UI 。请参阅this implementation以供参考。
关于您的问题:如果要在Firebase Auth中更新用户的数据,则需要使用Firebase Auth的功能来这样做:
- 更新其基本个人资料信息(docs)
- 使用
createProfileChangeRequest()
- 在请求对象上设置新值
- 致电
changeRequest?.commitChanges
进行更改
- 更新他们的电子邮件(docs)
- 使用
updateEmail(to: email)
一旦这些调用成功完成(使用相应的回调,记住这些是异步操作),您就可以在Firestore的profiles
集合中更新用户的信息。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。