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
相关产品推荐
相关产品推荐

