我目前正在构建一个简单的应用程序与一个登录/注册视图,以便更好地了解如何集成SwiftUI与Firebase
当我尝试更新用户数据时,我遇到了一点问题。我注意到,在作为一个用户注销然后作为一个不同的用户登录后,在点击登录按钮后,在FirstView上更新用户信息之前会有一秒的延迟。我正在想办法避免这种延迟的发生。
作为一个方面,我也有麻烦弄清楚如何顺利地从我的LoginView()导航到我的FirstView()。我有我的FirstView()内部的导航堆栈,但视图之间的过渡是非常突然的,缺乏NavigationLink动画。我如何纠正这个问题?
感谢!
以下是相关代码…
@main
struct AWSupportLoggerApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
@StateObject var viewModel = AppViewModel()
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(viewModel)
}
}
class AppDelegate:NSObject,UIApplicationDelegate{
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
FirebaseApp.configure()
return true
}
}
}
struct ContentView: View {
@EnvironmentObject var viewModel: AppViewModel
var body: some View {
NavigationView {
if viewModel.signedIn {
FirstView()
} else {
//.onAppear method is used for keyboard management (See Misc Functions...)
SignInView()
.onAppear(perform: UIApplication.shared.addTapGestureRecognizer)
.navigationBarHidden(true)
}
}
.onAppear {
viewModel.listen()
}
}
}
class AppViewModel: ObservableObject {
private var db = Firestore.firestore()
@Published var userInfo: User?
@Published var signedIn: Bool = false
var handle: AuthStateDidChangeListenerHandle?
let authRef = Auth.auth()
var authHandle : AuthStateDidChangeListenerHandle?
var rootInfoCollection : CollectionReference!
var userIdRef = ""
func fetchUserData(){
db.collection("Users").document("(userIdRef)").getDocument { document, error in
// Check for error
if error == nil {
// Check that this document exists
if document != nil && document!.exists {
self.userInfo = document.map { (documentSnapshot) -> User in
let data = documentSnapshot.data()
let uid = data?["uid"] as? UUID ?? UUID()
let company = data?["company"] as? String ?? ""
let name = data?["name"] as? String ?? ""
let admin = data?["admin"] as? Bool ?? false
let photo = data?["photo"] as? String ?? ""
return User(uid: uid, company: company, name: name, admin: admin, photo: photo)
}
}
}
}
}
func listen(){
handle = authRef.addStateDidChangeListener({ auth, user in
print(user?.email ?? "No User Found")
if let user = auth.currentUser {
self.userIdRef = user.uid
self.rootInfoCollection = Firestore.firestore().collection("/Users/")
DispatchQueue.main.async {
self.fetchUserData()
}
self.signedIn = true
} else {
self.signedIn = false
}
})
}
func signIn(email: String, password: String){
authRef.signIn(withEmail: email, password: password) { result, error in
guard result != nil, error == nil else {
return
}
}
}
func signOut(){
do {
try authRef.signOut()
} catch {
print(error)
}
}
func signUp(email: String, password: String, company: String, name: String, admin: Bool, photo: String){
authRef.createUser(withEmail: email, password: password) { result, error in
guard result != nil, error == nil else {
return
}
let db = Firestore.firestore()
//Success
db.collection("Users").document("(result!.user.uid)").setData(["company" : "(company)", "name" : "(name)", "admin" : admin, "photo" : "(photo)", "uid":result!.user.uid]) { error in
if error != nil {
print(error!)
}
}
}
}
func unbind() {
if let handle = handle {
authRef.removeStateDidChangeListener(handle)
}
}
}
struct FirstView: View {
@EnvironmentObject private var appViewModel: AppViewModel
var body: some View {
VStack{
Spacer()
VStack(spacing: 50){
NavigationLink(destination: Text("Test")){
awButton(content: "Request Support", backColor: Color(#colorLiteral(red: 0, green: 0.723585546, blue: 0.9907287955, alpha: 1)))
.shadow(color: Color.primary.opacity(0.5), radius: 20, x: 0, y: 20)
.rotation3DEffect(Angle(degrees:10), axis: (x: 10.0, y: 0, z: 0))
}
NavigationLink(destination: Text("Test")){
awButton(content: "Request Quote", backColor: Color(#colorLiteral(red: 0.9372549057, green: 0.3490196168, blue: 0.1921568662, alpha: 1)))
.shadow(color: Color.primary.opacity(0.5), radius: 20, x: 0, y: 20)
.rotation3DEffect(Angle(degrees:10), axis: (x: 10.0, y: 0, z: 0))
}
NavigationLink(destination: Text("Test")){
awButton(content: "Ticket Status", backColor: Color(#colorLiteral(red: 0.4666666687, green: 0.7647058964, blue: 0.2666666806, alpha: 1)))
.shadow(color: Color.primary.opacity(0.5), radius: 20, x: 0, y: 20)
.rotation3DEffect(Angle(degrees:10), axis: (x: 10.0, y: 0, z: 0))
}
}
Spacer()
}
.navigationBarBackButtonHidden(true)
.navigationTitle(appViewModel.userInfo?.company ?? "Test")
.navigationBarItems(leading: Button(action: {
appViewModel.signOut()
}) {
HStack {
Text("Sign Out")
}
},trailing: HStack{
Image(systemName: "bell")
.font(.system(size: 30))
// selectedImageArray.first!
// .resizable()
// .scaledToFit()
// .clipShape(Circle())
// .frame(width: 50, height: 50)
Text(appViewModel.userInfo?.name ?? "Tester")
.font(.system(size: 20))
})
}
}
您的导航状态取决于signedIn
。在真实侦听器中,您可以这样做:
DispatchQueue.main.async {
self.fetchUserData()
}
self.signedIn = true
这将设置signedIn
为true
,这将改变您的导航状态,然后在未来的一个不确定的时间,fetchUserData
将完成并更新用户数据(一旦网络调用完成)。
为了避免这种延迟(或者,实际上,只是为了避免在屏幕上看到没有更新的信息——延迟是网络调用不可避免的),在fetchUserData
完成之前不要设置signedIn
。因此,请删除侦听器内的行,并将其设置在self.userInfo =
行之后。