App Delegate设置UserDefaults后取值为空,Firebase无密码登录问题
问题原因
- UserDefaults 未即时同步:调用
set(_:forKey:)方法后,系统不会立刻将数据写入磁盘,会延后到合适的时机批量同步,如果你在存数据后立刻跳转读取,就会因为还没写入完成读到nil。 - 启动时序问题:如果用户点击登录链接时App处于完全杀死状态,App启动时会先初始化ViewController,再走AppDelegate的URL处理逻辑,如果你的登录方法是在ViewController的生命周期方法里主动调用的,调用时AppDelegate还没完成link的存储,自然读不到值。
- 存储逻辑未触发:如果
Auth.auth().isSignIn(withEmailLink: link)判断失败,就不会走存UserDefaults的逻辑,你可以先确认print("shit worked")有没有正常输出,如果没输出说明登录链接没有被正确识别。
解决方案
- 存储完成后强制同步,解决即时读取的问题
- 改用通知触发登录逻辑,解决启动时序问题
- 增加容错判断,避免强制解包崩溃
修改后的AppDelegate代码:
func handlePasswordlessSignIn(withURL url: URL) -> Bool { let link = url.absoluteString if Auth.auth().isSignIn(withEmailLink: link) { UserDefaults.standard.set(link, forKey: "Link") // 强制立刻写入磁盘 UserDefaults.standard.synchronize() print("shit worked") // 发送通知告知ViewController可以执行登录 NotificationCenter.default.post(name: NSNotification.Name("UserDidClickSignInLink"), object: nil) return true } print("shit aint work") return false }
修改后的ViewController代码:
override func viewDidLoad() { super.viewDidLoad() // 监听登录链接通知,收到通知后再执行登录 NotificationCenter.default.addObserver(self, selector: #selector(signInUserAfterEmailLinkClick), name: NSNotification.Name("UserDidClickSignInLink"), object: nil) } @objc func signInUserAfterEmailLinkClick(){ // 改用string(forKey:)直接读取字符串,避免类型转换失败 guard let link = UserDefaults.standard.string(forKey: "Link"), let email = EmailField.text, !email.isEmpty else { // 容错处理,可提示用户重新发送登录链接 return } self.link = link Auth.auth().signIn(withEmail: email, link: self.link) { [weak self] (user, error) in guard let self = self else { return } if let error = error { self.handleSignUpError(error: error) return } // 登录成功后删除已使用的链接,避免重复调用 UserDefaults.standard.removeObject(forKey: "Link") UserDefaults.standard.synchronize() } }
内容的提问来源于stack exchange,提问作者user11732444
相关产品推荐
相关产品推荐

