Xcode 9/Swift 4中Google Objective-C REST客户端库线程通知提前问题
我来帮你捋捋这个问题——这种通知提前触发的情况,在Swift混编Google Objective-C REST客户端库时真的挺常见的,大概率是你在异步回调的时机控制上出了问题,下面我给你拆解几个最可能的原因和解决办法:
1. 通知发送时机完全错误
最常见的坑就是:你把通知发送的代码写在了executeQuery调用之后,而不是真正的查询完成回调里面。比如像下面这种错误写法:
let driveService = GTLRDriveService() let query = GTLRDriveQuery_FilesList.query() // 发起异步查询 driveService.executeQuery(query) { ticket, response, error in // 这里本来应该处理结果再发通知,但你没这么做 } // 错误:这里的通知会在查询刚发起就发送,根本等不到线程完成! NotificationCenter.default.post(name: NSNotification.Name(rawValue: "QueryFinished"), object: nil)
正确做法:必须把通知放在completionHandler闭包内部,确认查询已经完成(不管成功失败)后再发送:
driveService.executeQuery(query) { ticket, response, error in // 先处理查询结果:比如打印错误、解析返回数据 if let err = error { print("查询失败:\(err.localizedDescription)") } else if let filesResponse = response as? GTLRDrive_FileList { print("拿到\(filesResponse.files?.count ?? 0)个文件") } // 确认完成后再发通知,还能把结果带过去 NotificationCenter.default.post( name: NSNotification.Name(rawValue: "QueryFinished"), object: nil, userInfo: ["response": response, "error": error] ) }
2. 混淆了同步/异步执行模式
Google的executeQuery默认是异步执行的,但如果你不小心设置了同步执行,或者用了错误的线程等待方式,也会出现通知提前的问题。比如你如果手动把查询放到了主线程同步执行,又用通知监听,可能会因为线程阻塞导致逻辑混乱。
排查点:检查你的GTLRService实例有没有设置过shouldFetchInBackground = false(这个属性会强制同步执行),如果有,改成true保持异步,然后严格在回调里处理完成逻辑。
3. 委托方式下的回调逻辑错误
如果你没用completionHandler,而是用了executeQuery:delegate:didFinishSelector:这种委托模式,那要检查你的委托方法是不是在开头就发送了通知:
// 错误示例:委托方法刚触发就发通知,没处理结果 - (void)finishedTicket:(GTLRServiceTicket *)ticket withReply:(id)reply error:(NSError *)error { // 提前发通知 [[NSNotificationCenter defaultCenter] postNotificationName:@"QueryFinished" object:nil]; // 后面才处理结果 }
正确做法:先处理完所有结果(错误判断、数据解析),再在方法末尾发送通知。
4. 线程上下文的问题
completionHandler默认是在后台线程执行的,如果你在后台线程直接发送通知,而主线程的监听逻辑没有正确处理(比如没切换回主线程更新UI),可能会给你一种“通知提前返回”的错觉。建议发送通知时切换到主线程:
driveService.executeQuery(query) { ticket, response, error in // 处理结果... DispatchQueue.main.async { NotificationCenter.default.post( name: NSNotification.Name(rawValue: "QueryFinished"), object: nil, userInfo: ["response": response, "error": error] ) } }
你可以先对照上面的几点检查你的代码,尤其是通知发送的位置,这是最容易踩的坑。如果还是有问题,可以把你的具体代码片段贴出来,我再帮你细化排查~
内容的提问来源于stack exchange,提问作者Christophe

