【问题标题】:Cannot convert value of type 'AuthDataResult?' to expected argument type 'User'无法转换“AuthDataResult”类型的值?到预期的参数类型“用户”
【发布时间】:2019-10-18 15:46:24
【问题描述】:

我正在尝试从我的用户模型中设置“当前”,以便以后可以使用 current.username 或 current.uid 等,但是我得到“无法转换类型 'AuthDataResult 的值?'到预期的参数类型“用户””错误。在过去的项目中,我能够按照最底部显示的教程来做到这一点。我现在拥有的代码显示在它上面。我已经检查了与堆栈溢出相关的其他问题,但找不到对我有帮助的东西。

(用户模型)

import Foundation
import UIKit
import FirebaseDatabase.FIRDataSnapshot

class User: Codable {

    let uid: String
    let username: String

    init(uid: String, username: String){
        self.uid = uid
        self.username = username
    }

    init?(snapshot: DataSnapshot) {
        guard let dict = snapshot.value as? [String : Any],
            let username = dict[Constants.Dict.username] as? String
            else { return nil }

        self.uid = snapshot.key
        self.username = username
    }

    private static var _current: User?

    static var current: User {
        guard let currentUser = _current else {
            fatalError("Error: current user doesn't exist")
        }
        return currentUser
   }

    class func setCurrent(_ user: User, writeToUserDefaults: Bool = false) {
        if writeToUserDefaults {
            if let data = try? JSONEncoder().encode(user) {
                UserDefaults.standard.set(data, forKey: Constants.UserDefaults.currentUser)
            }
        }

        _current = user
    }
}

(当前项目 - LoginVC)

@objc func handleSignIn() {
    guard let email = emailField.text else { return }
    guard let pass = passwordField.text else { return 

    Auth.auth().signIn(withEmail: email, password: pass) { user, error in
        if error == nil && user != nil {
            --> --> ERROR HERE "user" !!
            User.setCurrent(user, writeToUserDefaults: true)
            self.dismiss(animated: false, completion: nil)
        } else {
            print("Error logging in: \(error!.localizedDescription)")
        }
    }
}

(更新的解决方案)

Auth.auth().signIn(withEmail: email, password: pass) { user, error in
        if user?.user != nil {

            let user = user!.user

            UserService.show(forUID: user.uid) { (user) in
                User.setCurrent(user!, writeToUserDefaults: true)

                self.dismiss(animated: false, completion: nil)
            }
            ...

【问题讨论】:

  • 你能详细说明你为什么要这样做吗?如果您想获取已登录 Firebase 的 currentUser,则此 let user = Auth.auth().currentUser 如果您想更改用户,则您要更改的用户无论如何都需要进行身份验证,因此您需要调用 Auth.auth().signIn 函数。请注意,Firebase 有一个与您的“用户”类不同的“用户”类。如果您想拥有自己的,请将其命名为“MyUser”。
  • 如果我有当前用户,我可以检索其他内容,例如 current.time 或 current.score。我正在尝试像以前的项目一样制作电流,以便轻松地从 firebase 检索有关用户的信息。
  • 我有一个解决方案,但在发布之前还有几个问题;没有说明,但您是否尝试使用单例模式来处理用户信息?我问这个是因为 UserService 看起来像你。此外,您的评论因此很容易从 firebase 中检索有关用户的信息,但您的问题中没有代码可以从 Firebase 中检索任何内容,而不是进行身份验证。如果您能详细说明一下,可能会有一个简单的解决方案。
  • 是的。它是单例模式。我的 UserService 中有用于检索数据的代码。我在上面添加了我的整个用户模型。
  • 我研究这段代码已经有一段时间了,如果您只想在整个应用程序中使用单例来访问用户信息,这似乎过于复杂。还不清楚调用 current 时会发生什么 - 它返回 User 但出于什么目的?换句话说,如果您想要当前的用户名或 uid,使用 let name = User.shared.namelet uid = User.shared.uid 会不会更简单?

标签: swift firebase authentication login firebase-authentication


【解决方案1】:

看来,您只是弄乱了两种不同的方法。在您过去的项目中,它是 FirebaseUI-iOS 的方法:

func authUI(_ authUI: FUIAuth, didSignInWith user: FIRUser?, error: Error?)

来自协议“FUIAuthDelegate”。

顺便说一句,这个方法现在在firebase sources 中声明为“已弃用”:

- (void)authUI:(FUIAuth *)authUI
    didSignInWithUser:(nullable FIRUser *)user
                error:(nullable NSError *)error
__attribute__((deprecated("Instead use authUI:didSignInWithAuthDataResult:error:")));

如您所见,它具有名为“user”的“FIRUser *”类型的参数。

但在当前项目中,您使用 firebase-ios-sdk 的“Auth”类的“signIn”方法。让我们在sources of Firebase中寻找“signIn”的签名:

    - (void)signInWithEmail:(NSString *)email
                   password:(NSString *)password
                 completion:(nullable FIRAuthDataResultCallback)completion {

where "FIRAuthDataResultCallback" is:

/** @typedef FIRAuthDataResultCallback
    @brief The type of block invoked when sign-in related events complete.
    @param authResult Optionally; Result of sign-in request containing both the user and
       the additional user info associated with the user.
    @param error Optionally; the error which occurred - or nil if the request was successful.
 */
typedef void (^FIRAuthDataResultCallback)(FIRAuthDataResult *_Nullable authResult,
                                          NSError *_Nullable error)
    NS_SWIFT_NAME(AuthDataResultCallback);

因此它具有名为“authResult”的“FIRAuthDataResult *”类型的第一个参数(现代 Swift 中未保留的闭包参数的命名!)。您将此参数命名为“用户”并对其类型做出错误假设 - 用户。

什么是“FIRAuthDataResult *”? Let's look to sources once more:

NS_SWIFT_NAME(AuthDataResult)
@interface FIRAuthDataResult : NSObject

/**...*/
- (instancetype)init NS_UNAVAILABLE;

/** @property user
    @brief The signed in user.
 */
@property(nonatomic, readonly) FIRUser *user;

/** @property additionalUserInfo
    @brief If available contains the additional IdP specific information about signed in user.
 */
@property(nonatomic, readonly, nullable) FIRAdditionalUserInfo *additionalUserInfo;

@end

所以这只是用户和附加信息的容器。

我认为,您当前的代码应该是这样编译的:

@objc func handleSignIn() {
    guard let email = emailField.text else { return }
    guard let pass = passwordField.text else { return 

    Auth.auth().signIn(withEmail: email, password: pass) { authDataResult, error in
        guard let authDataResult = authDataResult,
            let user = authDataResult.user,
            error == nil else {
            print("Error logging in: \(error?.localizedDescription ?? "no description")")
            return
        }
        User.setCurrent(user, writeToUserDefaults: true)
        self.dismiss(animated: false, completion: nil)
    }
}

免责声明:我并没有真正尝试编译它!

【讨论】:

  • 嗨。谢谢你的解释。我很感激。尽管对于 let user = authDataResult.user 部分,我收到错误“条件绑定的初始化程序必须具有可选类型,而不是'用户'”
  • 尝试完全删除此行:let user = authDataResult.user,。并重写:User.setCurrent(user, writeToUserDefaults: true)User.setCurrent(authDataResult.user, writeToUserDefaults: true)
  • 对于那个新的 User.setCurrent...“无法将“用户”类型的值转换为预期的参数类型“用户””我对这个错误感到困惑,因为它们都是“用户”类型。
  • 在当前项目中,您声明了class User: Codable {。所以方法class func setCurrent(_ user: User, writeToUserDefaults: Bool = false) { - 等待你的User。但是authDataResult.user 真的是FIRUser*。所以在你过去的项目中似乎很神奇UserService.show(forUID: user.uid) { (user) in。我可以假设它是这样工作的:它得到了user 类型为FIRUser *uid 类型为String 的参数user.uid,然后它调用了完成{ (user) in,此时user 已经是你的User 类型。所以让我们在那里搜索隐藏的封面FIRUser *User
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-01-07
  • 1970-01-01
  • 2021-09-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多