我成功将其他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, password: String, completion: @escaping (_ profile: UserProfile?,
_ error: Error?) -> Void) {
Auth.auth().signIn(withEmail: email, password: password) { (result, 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) in
if let error = error {
print("Error while fetching the user profile: \(error)")
completion(nil, 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, completion: @escaping (_ 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, completion: @escaping (_ profile: UserProfile?, _ 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()
}
}
答案 0 :(得分:2)
一些注意事项:
didChange = PassthroughSubject
上实现SessionStore
-一旦您更改了任何@Published
属性,就会通知所有订阅者。User
结构-只需使用从Firebase Auth获得的结构即可-它具有您需要照顾的所有属性。NavigationView
中,将navigationBarTitle
设置为Settings
-这应该为您提供典型的设置UI 。请参阅this implementation以供参考。关于您的问题:如果要在Firebase Auth中更新用户的数据,则需要使用Firebase Auth的功能来这样做:
createProfileChangeRequest()
changeRequest?.commitChanges
进行更改updateEmail(to: email)
一旦这些调用成功完成(使用相应的回调,记住这些是异步操作),您就可以在Firestore的profiles
集合中更新用户的信息。