iOS Swift调用Google Vision API手写识别返回nil问题排查
问题排查方案
核心错误原因&修复项
- 实例生命周期错误:你当前将
GoogleVision实例gv声明为imagePickerController方法内的局部变量,方法执行完毕后实例会被ARC自动释放,异步回调还未返回就已经被销毁,自然无法拿到响应结果。你需要将gv提升为当前控制器的全局属性,保证回调执行时实例依然存在。 - API配置错误:
- 确认代码中的
API-KEy已替换为你自己的、已开通Google Cloud Vision API权限、完成账单绑定的有效密钥 - 你使用的第三方CocoaPod封装默认可能使用普通印刷体文本识别类型
TEXT_DETECTION,要识别手写文本必须指定识别类型为DOCUMENT_TEXT_DETECTION,需要检查对应封装的run方法是否支持传入识别类型参数,手动切换为文档/手写识别模式
- 确认代码中的
- 图片参数错误:iOS相机输出的UIImage默认携带方向参数
imageOrientation,未修正方向的图片传给Google Vision会导致识别失败,建议先对图片做方向归一化处理后再传入API
修正后的示例代码
// 首先在当前控制器类内声明GoogleVision为全局属性 var gv: GoogleVision? func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { picker.dismiss(animated: true, completion: nil) guard let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage else { return showAlert(title: "Error", message: "Image not Found") } // 先修正图片方向 let fixedImage = image.fixedOrientation() takePhotoView.image = fixedImage // 初始化实例赋值给全局属性 gv = GoogleVision.init(apiKey: "替换为你的有效API密钥") // 注意如果封装支持指定识别类型,一定要传DOCUMENT_TEXT_DETECTION gv?.run(image: fixedImage, feature: .documentTextDetection) { text, error in guard let text = text, error == nil else { print("识别错误:\(error?.localizedDescription ?? "未知错误")") // 用完可置空 self.gv = nil return } print("识别结果:\(text)") self.gv = nil } } // 扩展UIImage实现方向修正 extension UIImage { func fixedOrientation() -> UIImage { guard imageOrientation != .up else { return self } var transform = CGAffineTransform.identity switch imageOrientation { case .down, .downMirrored: transform = transform.translatedBy(x: size.width, y: size.height) transform = transform.rotated(by: .pi) case .left, .leftMirrored: transform = transform.translatedBy(x: size.width, y: 0) transform = transform.rotated(by: .pi / 2) case .right, .rightMirrored: transform = transform.translatedBy(x: 0, y: size.height) transform = transform.rotated(by: -.pi / 2) default: break } switch imageOrientation { case .upMirrored, .downMirrored: transform = transform.translatedBy(x: size.width, y: 0) transform = transform.scaledBy(x: -1, y: 1) case .leftMirrored, .rightMirrored: transform = transform.translatedBy(x: size.height, y: 0) transform = transform.scaledBy(x: -1, y: 1) default: break } guard let cgImage = cgImage, let context = CGContext(data: nil, width: Int(size.width), height: Int(size.height), bitsPerComponent: cgImage.bitsPerComponent, bytesPerRow: 0, space: cgImage.colorSpace!, bitmapInfo: cgImage.bitmapInfo.rawValue) else { return self } context.concatenate(transform) switch imageOrientation { case .left, .leftMirrored, .right, .rightMirrored: context.draw(cgImage, in: CGRect(x: 0, y: 0, width: size.height, height: size.width)) default: context.draw(cgImage, in: CGRect(x: 0, y: 0, width: size.width, height: size.height)) } guard let fixedCGImage = context.makeImage() else { return self } return UIImage(cgImage: fixedCGImage) } }
额外排查建议
如果修改后还是返回空,可以直接在回调里打印完整的error对象,而不是只打印localizedDescription,可以拿到更详细的错误码,比如403代表API权限问题,400代表参数错误。
内容的提问来源于stack exchange,提问作者Zubair Amjad
相关产品推荐
相关产品推荐

