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

iOS Swift调用Google Vision API手写识别返回nil问题排查

问题排查方案

核心错误原因&修复项

  • 实例生命周期错误:你当前将GoogleVision实例gv声明为imagePickerController方法内的局部变量,方法执行完毕后实例会被ARC自动释放,异步回调还未返回就已经被销毁,自然无法拿到响应结果。你需要将gv提升为当前控制器的全局属性,保证回调执行时实例依然存在。
  • API配置错误:
    1. 确认代码中的API-KEy已替换为你自己的、已开通Google Cloud Vision API权限、完成账单绑定的有效密钥
    2. 你使用的第三方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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 00:36:04