You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift中Firebase单函数更新邮箱用户名:回调未执行求助

问题原因及修复方案

Ah, I spot the immediate issue here—your updateDetails function never invokes the updateComplete closure you pass into it! That’s exactly why the callback code in saveChangesButtonPressed never runs, even though the auth and database updates work as expected.

Let’s break this down and fix it properly:

1. Core Problem: Missing Closure Invocation

Looking through your updateDetails implementation, there’s nowhere you call updateComplete(error:)—not in the email update success/failure blocks, nor in the display name update blocks. The closure is passed into the function, but never triggered, so the code waiting for it in saveChangesButtonPressed has no way to execute.

2. Bonus Issue: Uncoordinated Async Operations

On top of that, you’re running two independent async operations (updateEmail and commitChanges) in parallel. Right now, if one fails and the other succeeds, your user gets mixed error alerts, and you can’t properly report the overall result to the caller. We should coordinate these tasks so we only notify the caller once both operations are done.

Fixed Code Implementation

Here’s how to adjust updateDetails to fix both issues, using a DispatchGroup to wait for both async tasks to complete:

func updateDetails(withEmail email: String, andDisplayName displayName: String, updateComplete: @escaping(_ error: Error?) -> ()) { 
    guard let currentUser = Auth.auth().currentUser, let userId = user?.uid else {
        updateComplete(NSError(domain: "AuthError", code: -1, userInfo: [NSLocalizedDescriptionKey: "Unable to access current user"]))
        return
    }
    
    let group = DispatchGroup()
    var combinedError: Error?
    
    // Update email
    group.enter()
    currentUser.updateEmail(to: email) { error in
        defer { group.leave() }
        if let error = error {
            combinedError = error
        } else {
            let ref = Database.database().reference().child("Users").child(userId).child("email")
            ref.setValue(currentUser.email)
        }
    }
    
    // Update display name
    group.enter()
    let changeRequest = currentUser.createProfileChangeRequest()
    changeRequest.displayName = displayName
    changeRequest.commitChanges { error in
        defer { group.leave() }
        if let error = error {
            combinedError = error
        } else {
            let ref = Database.database().reference().child("Users").child(userId).child("name")
            ref.setValue(currentUser.displayName)
            DispatchQueue.main.async {
                self.welcomeLabel.text = "Hi, \(displayName)"
            }
        }
    }
    
    // Wait for both tasks to finish, then call the completion closure
    group.notify(queue: .main) {
        updateComplete(combinedError)
    }
}

You can keep your saveChangesButtonPressed mostly the same—now the callback will actually fire as expected:

@IBAction func saveChangesButtonPressed(_ sender: Any) { 
    guard let email = emailTextField.text, !email.isEmpty,
          let displayName = currentUserNameTextField.text, !displayName.isEmpty else {
        createError(title: "Error", message: "Email and name fields must not be blank")
        return
    } 
    
    updateDetails(withEmail: email, andDisplayName: displayName) { error in 
        if let error = error {
            self.createError(title: "Update Failed", message: error.localizedDescription)
        } else {
            self.createError(title: "Success", message: "Your details have been updated!")
        }
    } 
}

Key Changes Explained

  • Added closure invocation: We now call updateComplete inside group.notify once both async tasks are done, passing along any error that occurred.
  • Coordinated async tasks: DispatchGroup ensures we wait for both the email and display name updates to finish before notifying the caller.
  • Moved error handling to caller: Instead of showing error alerts inside updateDetails, we let saveChangesButtonPressed handle feedback—this keeps your code more modular and reusable.
  • Safe optional unwrapping: Added guard clauses to handle cases where currentUser or user?.uid might be nil, which prevents crashes and properly reports errors.

内容的提问来源于stack exchange,提问作者Rob

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 04:12:23