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

Serial DispatchQueue未按预期执行,请求技术协助

问题排查与修复方案

问题根源

你的block1里调用的restorePreviousSignIn是异步方法——调用该方法后,block1会立刻执行完毕,而用户邮箱的赋值操作是在它的回调闭包里才会触发。所以当block1.notify触发block2时,self.email还没被更新,导致getData拿到的是空值。

修复方案

方案一:将后续任务嵌入异步回调内部

直接在restorePreviousSignIn的成功回调里启动后续任务,确保邮箱赋值完成后再执行:

let serialQueue = DispatchQueue(label: "com.queue.serial")
serialQueue.async {
    GIDSignIn.sharedInstance.restorePreviousSignIn { [weak self] user, error in
        guard let self = self else { return }
        if error != nil || user == nil {
            print("unable to identify user")
            DispatchQueue.main.async {
                self.todoListTable.reloadData()
            }
            return
        }
        
        guard let email = user!.profile?.email else {
            print("user has no email")
            DispatchQueue.main.async {
                self.todoListTable.reloadData()
            }
            return
        }
        
        self.email = email
        print("email is: \(self.email)")
        
        // 邮箱获取完成后执行数据读取
        self.getData(email)
        
        // 刷新表格视图
        DispatchQueue.main.async {
            self.todoListTable.reloadData()
        }
    }
}

方案二:用DispatchGroup等待异步回调完成

如果需要保留任务拆分的结构,可以用DispatchGroup等待异步回调结束:

let serialQueue = DispatchQueue(label: "com.queue.serial")
let group = DispatchGroup()

group.enter()
serialQueue.async {
    GIDSignIn.sharedInstance.restorePreviousSignIn { [weak self] user, error in
        defer { group.leave() }
        guard let self = self else { return }
        if error != nil || user == nil {
            print("unable to identify user")
            return
        }
        self.email = user!.profile?.email ?? ""
        print("email is: \(self.email)")
    }
}

// 等待邮箱获取完成后执行后续操作
group.notify(queue: serialQueue) { [weak self] in
    guard let self = self else { return }
    self.getData(self.email)
    
    DispatchQueue.main.async {
        self.todoListTable.reloadData()
    }
}

方案三:用async/await(Swift 5.5+推荐)

如果你的项目基于Swift 5.5及以上版本,推荐用异步等待语法,代码更简洁易读:
首先封装异步版的登录恢复方法:

extension GIDSignIn {
    func restorePreviousSignInAsync() async throws -> GIDGoogleUser {
        return try await withCheckedThrowingContinuation { continuation in
            restorePreviousSignIn { user, error in
                if let error = error {
                    continuation.resume(throwing: error)
                } else if let user = user {
                    continuation.resume(returning: user)
                } else {
                    continuation.resume(throwing: NSError(domain: "SignInError", code: -1, userInfo: [NSLocalizedDescriptionKey: "User not found"]))
                }
            }
        }
    }
}

然后在视图逻辑中调用:

Task {
    do {
        let user = try await GIDSignIn.sharedInstance.restorePreviousSignInAsync()
        guard let email = user.profile?.email else {
            print("user has no email")
            DispatchQueue.main.async {
                self.todoListTable.reloadData()
            }
            return
        }
        self.email = email
        print("email is: \(self.email)")
        
        // 切换到串行队列执行耗时的数据读取操作
        await serialQueue.async {
            self.getData(self.email)
        }
        
        DispatchQueue.main.async {
            self.todoListTable.reloadData()
        }
    } catch {
        print("unable to identify user: \(error)")
        DispatchQueue.main.async {
            self.todoListTable.reloadData()
        }
    }
}

注意事项

  • 务必使用[weak self]避免循环引用,防止内存泄漏
  • 错误分支也要处理表格刷新,避免界面一直处于加载状态

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 03:15:24