Сбой пользователя без нуля при развертывании — Firebase, SwiftUI

#firebase #google-cloud-firestore #swiftui #swift5

#Firebase #Google-cloud-firestore #SwiftUI #swift5

Вопрос:

Разворачивание значений обычным способом в представлениях SwiftUI запрещено, но вы можете сделать это в пределах body , скажем, an HStack или a VStack . Ниже я пытаюсь развернуть пользователя, который, как я был уверен, не был нулевым. My LoginView позволяет пользователю создать учетную запись в Firebase Firestore, регистрирует вас, если пользователь вводит правильные значения, и отображает вид предупреждения, если нет.

На моем HomeView.swift первом экране после запуска я вылетаю при попытке представить изображение пользователя. Однако, когда я разворачиваю пользователя, пользователь по-прежнему равен нулю в консоли. Я думаю, это связано с тем, что Firebase не успевает загрузить изображение до инициализации представления. Но я могу ошибаться. Справка.

 
struct HomeProfileView: View {
    @EnvironmentObject var session: SessionStore
    @State var showDashboard = false
    var user: User?
    
    var body: some View {
        if user != nil {
            URLImage(URL(string: user!.profileImageUrl)!, content: {
                $0.image
                    .resizable()
                    .aspectRatio(contentMode: .fill)
                    .clipShape(Circle())
            })
            .frame(width: 50, height: 50)
            .background(Color(#colorLiteral(red: 0.9490196078, green: 0.9490196078, blue: 0.9490196078, alpha: 1)))
            .clipShape(Circle())
            .shadow(color: Color.black.opacity(0.1), radius: 1, x: 0, y: 1)
            .shadow(color: Color.black.opacity(0.2), radius: 10, x: 0, y: 10)
            .sheet(isPresented: $showDashboard) {
                DashboardView(showDashboard: $showDashboard)
            }
        }
    }
}


  

Я не думаю, что здесь мне нужен необязательный пользователь, но я не знаю, как безопасно развернуть пользователя в противном случае. Другая версия использует сеанс EnvironmentObject для доступа к текущему зарегистрированному пользователю.

 
struct HomeProfileView: View {
    @EnvironmentObject var session: SessionStore
    @State var showDashboard = false
    
    var body: some View {
        if session.isLoggedIn {
            URLImage(URL(string: session.userSession!.profileImageUrl)!, content: {
                $0.image
                    .resizable()
                    .aspectRatio(contentMode: .fill)
                    .clipShape(Circle())
            })
            .frame(width: 50, height: 50)
            .background(Color(#colorLiteral(red: 0.9490196078, green: 0.9490196078, blue: 0.9490196078, alpha: 1)))
            .clipShape(Circle())
            .shadow(color: Color.black.opacity(0.1), radius: 1, x: 0, y: 1)
            .shadow(color: Color.black.opacity(0.2), radius: 10, x: 0, y: 10)
            .sheet(isPresented: $showDashboard) {
                DashboardView(showDashboard: $showDashboard)
            }
        }
    }
}


  

session Свойство принадлежит SessionStore классу и, по сути, является необязательным User .

 
import Foundation
import Combine
import Firebase

class SessionStore: ObservableObject {
    
    @Published var isLoggedIn: Bool = UserDefaults.standard.bool(forKey: "isLoggedIn") {
        didSet {
            UserDefaults.standard.set(self.isLoggedIn, forKey: "isLoggedIn")
        }
    }

    var userSession: User?
    
    var handle: AuthStateDidChangeListenerHandle?
    
    func listenAuthenticationState() {
        handle = Auth.auth().addStateDidChangeListener({ (auth, user) in
            if let user = user {
                print(user.email as Any)
                let firestoreUserId = Ref.FIRESTORE_DOCUMENT_USERID(userId: user.uid)
                firestoreUserId.getDocument { (document, error) in
                    if let dict = document?.data() {
                        guard let decodeUser = try? User.init(fromDictionary: dict) else { return }
                        self.userSession = decodeUser
                    }
                }
                self.isLoggedIn = true
            } else {
                print("User is Logged Out")
                self.isLoggedIn = false
                self.userSession = nil
            }
        })
    }
}

  

Зарегистрированный пользователь действительно вошел в систему, но я не могу получить доступ к каким-либо свойствам.

Ответ №1:

Установите isLoggedIn точно в том месте, где вы установили UserSession, потому что это выполняется в асинхронном обратном вызове, и сделайте это в основной очереди (для правильного обновления пользовательского интерфейса)

 firestoreUserId.getDocument { (document, error) in
    if let dict = document?.data() {
        guard let decodeUser = try? User.init(fromDictionary: dict) else { return }
        DispatchQueue.main.async {
           self.userSession = decodeUser
           self.isLoggedIn = true
        }
    }
}
  

Комментарии:

1. мой session.userSession по-прежнему равен нулю, и я все еще сбой. Хороший вызов Dispatch.main.async , хотя

2. ошибка возникает в моем profileImageUrl, а именно; session.userSession.profileImageUrl

Ответ №2:

У меня это работает. Не уверен, насколько это масштабируемо, но я делаю not равно нулю. Я также вставил его в кнопку, чтобы переключить его с an onTapGesture .

 
struct HomeProfileView: View {
    @EnvironmentObject var session: SessionStore
    @State var showDashboard = false
    
    var body: some View {
        if session.isLoggedIn {
            if (session.userSession?.profileImageUrl) != nil {
                Button(action: { self.showDashboard.toggle() } ) {
                    URLImage(URL(string: session.userSession!.profileImageUrl)!, content: {
                        $0.image
                            .resizable()
                            .aspectRatio(contentMode: .fill)
                            .clipShape(Circle())
                    })
                    .frame(width: 50, height: 50)
                    .background(Color(#colorLiteral(red: 0.9490196078, green: 0.9490196078, blue: 0.9490196078, alpha: 1)))
                    .clipShape(Circle())
                    .shadow(color: Color.black.opacity(0.1), radius: 1, x: 0, y: 1)
                    .shadow(color: Color.black.opacity(0.2), radius: 10, x: 0, y: 10)
                    .sheet(isPresented: $showDashboard) {
                        DashboardView(showDashboard: $showDashboard)
                    }
                }
            }
        }
    }
}