【问题标题】:How to update EnvironmentObject variable from Coordinator class?如何从 Coordinator 类更新 EnvironmentObject 变量?
【发布时间】:2020-10-07 18:28:26
【问题描述】:

当用户通过 FB 登录按钮完成授权时,我正在使用 Coordinator(符合 LoginButtonDelegate)对象来接收用户数据(个人资料、姓名)。 Coordinator().userId 属性使用用户 ID 进行更新,但我需要将其传递到 LoginView 1 级并更新名为 thisSession 的 EnvironmentObject(以某种方式使 thisSession.userId = Coordinator().userId)。

有没有办法做到这一点?我尝试使用 ObservableObject/Published 属性,但我无法从 Coordinator 更新父对象的属性。

另一个想法是订阅 Auth.auth() 更改,但它似乎太复杂而且有点“老派”的解决方案。有一些我想念的简单方法。

任何提示/想法?

import SwiftUI
import FirebaseCore
import FirebaseAuth
import FBSDKLoginKit
import FBSDKCoreKit

struct LoginView: View {
    @EnvironmentObject var thisSession: CurrentSession
    @ObservedObject var mainData = MainViewModel()

    var facebookView = facebook()

    var body: some View {
        VStack {
            facebookView.frame(width: 240, height: 50)
            Text("\(self.thisSession.userId ?? "none")")
        }
    }
}

struct LoginView_Previews: PreviewProvider {
    static var previews: some View {
        LoginView().environmentObject(CurrentSession())
    }
}


struct facebook: UIViewRepresentable {
    @EnvironmentObject var thisSession: CurrentSession
    @ObservedObject var coordinator = Coordinator()

    func makeCoordinator() -> facebook.Coordinator {
        return self.coordinator
        //facebook.Coordinator()
    }

    func makeUIView(context: UIViewRepresentableContext<facebook>) -> FBLoginButton {

        let button = FBLoginButton()
        button.delegate = self.coordinator
        print("UPDATED")

        return button
    }

    func updateUIView(_ uiView: FBLoginButton, context: UIViewRepresentableContext<facebook>) {
    }

    class Coordinator: NSObject, LoginButtonDelegate, ObservableObject {
        @Published var userId: String?
        func loginButton(_ loginButton: FBLoginButton, didCompleteWith result: LoginManagerLoginResult?, error: Error?) {

            if error != nil{

                print((error?.localizedDescription)!)
                return
            }
            if AccessToken.current != nil{

                let credential = FacebookAuthProvider.credential(withAccessToken: AccessToken.current!.tokenString)

                Auth.auth().signIn(with: credential) { (res,er) in

                    if er != nil{
                        print((er?.localizedDescription)!)
                        return

                    }
                    print("email: \(String(describing: res?.user.email))")
                    print("name: \(String(describing: res?.user.displayName))")
                    self.userId = String(describing: res?.user.displayName)
                }
            }
        }

        func loginButtonDidLogOut(_ loginButton: FBLoginButton) {
            print("logged out")
            try! Auth.auth().signOut()

        }
    }

}

【问题讨论】:

    标签: swift firebase-authentication swiftui coordinator-pattern


    【解决方案1】:

    尝试以下操作,因为协调器是在更新期间创建的,环境对象应该已经注入并存在,所以它应该可以工作

    struct facebook: UIViewRepresentable {
        @EnvironmentObject var thisSession: CurrentSession
    
        func makeCoordinator() -> facebook.Coordinator {
            Coordinator(session: thisSession)              // << here !!
        }
    
        func makeUIView(context: UIViewRepresentableContext<facebook>) -> FBLoginButton {
    
            let button = FBLoginButton()
            button.delegate = self.coordinator
            print("UPDATED")
    
            return button
        }
    
        func updateUIView(_ uiView: FBLoginButton, context: UIViewRepresentableContext<facebook>) {
        }
    
        class Coordinator: NSObject, LoginButtonDelegate, ObservableObject {
            let session: CurrentSession
            init(session: CurrentSession) {
                self.session = session
            }
    
            func loginButton(_ loginButton: FBLoginButton, didCompleteWith result: LoginManagerLoginResult?, error: Error?) {
    
                if error != nil{
    
                    print((error?.localizedDescription)!)
                    return
                }
                if AccessToken.current != nil{
    
                    let credential = FacebookAuthProvider.credential(withAccessToken: AccessToken.current!.tokenString)
    
                    Auth.auth().signIn(with: credential) { (res,er) in
    
                        if er != nil{
                            print((er?.localizedDescription)!)
                            return
    
                        }
                        print("email: \(String(describing: res?.user.email))")
                        print("name: \(String(describing: res?.user.displayName))")
    
                        DispatchQueue.main.async {   // << here 
                            self.session.userId = String(describing: res?.user.displayName)
                        }
                    }
                }
            }
    
            func loginButtonDidLogOut(_ loginButton: FBLoginButton) {
                print("logged out")
                try! Auth.auth().signOut()
    
            }
        }
    
    }
    

    【讨论】:

    • 不确定你说得对不对。我想用来自 Coordinator 的数据更新 环境对象
    • @eugene_prg,EnvironmentObject 只是对 ObservableObject 引用的观察者包装,因此在提议的解决方案中,此引用被传递到协调器,并按预期进行更改。
    • 协调器如何访问 EnvironmentObject 的引用?我们甚至在创建协调器时不传递引用,我们传递 VALUE。那么它是如何更新的呢?
    猜你喜欢
    • 2021-04-12
    • 1970-01-01
    • 2019-12-17
    • 1970-01-01
    • 2023-03-15
    • 2021-04-21
    • 2022-08-03
    • 2021-10-14
    • 1970-01-01
    相关资源
    最近更新 更多