最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

ios - VNDetectBarcodesRequest throws an error in Swift Playground - Stack Overflow

programmeradmin2浏览0评论

My simple code written in Swift Playground is very simple and short (based on popular tutorials):

import UIKit
@preconcurrency import Vision
var queue = DispatchQueue.global()
extension UIImage {
    @MainActor func detectBarcodes(completion: @Sendable @escaping ([VNBarcodeObservation]) ->()) {
        let request = VNDetectBarcodesRequest()
        request.queueFor(image: self) { result in
            completion(result as? [VNBarcodeObservation] ?? [])
        }
    }
}

extension VNDetectBarcodesRequest {
    @MainActor func queueFor(image: UIImage, completion: @Sendable @escaping ([Any]?) -> ()) {
        let handler = VNImageRequestHandler(cgImage: image.cgImage!, orientation: .up, options: [:])
        queue.async {
            do {
                let w = "ok here 1✅"
                try handler.perform([self])
                let b = "ok here 2✅"
            } catch {
                let c = "error here❌" //<== this line is printed on console. Why?
            }
        }
    }
}
let image = UIImage(named: "5.jpg")!
image.detectBarcodes { barcodes in
    for barcode in barcodes {
        let a = barcode.payloadStringValue
    }
}

The image for scanning:

My simple code written in Swift Playground is very simple and short (based on popular tutorials):

import UIKit
@preconcurrency import Vision
var queue = DispatchQueue.global()
extension UIImage {
    @MainActor func detectBarcodes(completion: @Sendable @escaping ([VNBarcodeObservation]) ->()) {
        let request = VNDetectBarcodesRequest()
        request.queueFor(image: self) { result in
            completion(result as? [VNBarcodeObservation] ?? [])
        }
    }
}

extension VNDetectBarcodesRequest {
    @MainActor func queueFor(image: UIImage, completion: @Sendable @escaping ([Any]?) -> ()) {
        let handler = VNImageRequestHandler(cgImage: image.cgImage!, orientation: .up, options: [:])
        queue.async {
            do {
                let w = "ok here 1✅"
                try handler.perform([self])
                let b = "ok here 2✅"
            } catch {
                let c = "error here❌" //<== this line is printed on console. Why?
            }
        }
    }
}
let image = UIImage(named: "5.jpg")!
image.detectBarcodes { barcodes in
    for barcode in barcodes {
        let a = barcode.payloadStringValue
    }
}

The image for scanning:

Share Improve this question asked Feb 17 at 11:27 Bartłomiej SemańczykBartłomiej Semańczyk 61.8k52 gold badges246 silver badges398 bronze badges Recognized by Mobile Development Collective 1
  • Replace let c = "error here" with print(error) so you can see the actual error. – HangarRash Commented Feb 18 at 1:19
Add a comment  | 

2 Answers 2

Reset to default 1

Short Answer

"Could not create inference context" is basically telling you that simulator/playgrounds cant run VisionKit code.

To get a result you must run your code on a device such as a physical iPhone or on a Mac, etc.

Long Answer

You have a lot of unnecessary closures, stick with synchronous code.

extension UIImage {
    func detectBarcodes() throws -> [VNBarcodeObservation] {
        let request = VNDetectBarcodesRequest()
        try request.queueFor(image: self)
        return request.results ?? []
    }
}

extension VNDetectBarcodesRequest {
    func queueFor(image: UIImage) throws  {
        let handler = VNImageRequestHandler(cgImage: image.cgImage!, orientation: .up, options: [:])
            do {
                let w = "ok here 1✅"
                try handler.perform([self])
                let b = "ok here 2✅"
            } catch {
                let c = "error here❌"
                throw error //Throw the error instead of ignoring it.
            }
    }
}

then you can call something like

let results = try image.detectBarcodes()

Then you can use a task group for multiple images and run them asynchronously

let images = [UIImage(named: "ckVxHugYl.png.jpeg")!, UIImage(named: "ckVxHugYl.png.jpeg")!, UIImage(named: "ckVxHugYl.png.jpeg")!]

let task = Task {
    do {
        try await withThrowingTaskGroup(of: [VNBarcodeObservation].self) { group in
            for image in images {
                group.addTask {
                    try image.detectBarcodes()
                }

            }
            for try await result in group {
                for barcode in result {
                    print(barcode.payloadStringValue)
                }
                print(result)
            }
        }
    } catch {
        print(error)
    }
}

or run it synchronously

for image in images {
    let results = try image.detectBarcodes()
    for barcode in results {
        print(barcode.payloadStringValue)
    }
}

If you want to keep @MainActor for some reason this approach with actually work with it, GCD is not compatible with the new Concurrency.

Once you run the updated code on a physical device you'll see your url in the console

https://joytst.page.link/QAZtSG1KJ7txNVgN8

As stated in this answer: https://stackoverflow/a/75902996/29516370, you should add

#if targetEnvironment(simulator)
    if #available(iOS 17.0, *) {
        let allDevices = MLComputeDevice.allComputeDevices
        
        for device in allDevices {
            if(device.description.contains("MLCPUComputeDevice")){
                request.setComputeDevice(.some(device), for: .main)
                break
            }
        }
        
    } else {
        request.usesCPUOnly = true
    }
#endif

Tip: i found a solution simply by printing error.localizedDescription: "Could not create inference context":

import UIKit

@preconcurrency import Vision
let visionQueue = DispatchQueue(label: "com.example.vision")
extension UIImage {
    @MainActor func detectBarcodes(completion: @Sendable @escaping ([VNBarcodeObservation]) ->()) {
        let request = VNDetectBarcodesRequest()
        
#if targetEnvironment(simulator)
        if #available(iOS 17.0, *) {
            let allDevices = MLComputeDevice.allComputeDevices
            
            for device in allDevices {
                if(device.description.contains("MLCPUComputeDevice")){
                    request.setComputeDevice(.some(device), for: .main)
                    break
                }
            }
            
        } else {
            request.usesCPUOnly = true
        }
#endif
        
        request.queueFor(image: self) { result in
            completion(result as? [VNBarcodeObservation] ?? [])
        }
    }
}

extension VNDetectBarcodesRequest {
    @MainActor func queueFor(image: UIImage, completion: @Sendable @escaping ([Any]?) -> ()) {
        let handler = VNImageRequestHandler(cgImage: image.cgImage!, orientation: .up, options: [:])
        DispatchQueue.main.async {
            do {
                let w = "ok here 1✅"
                try handler.perform([self])
                let b = "ok here 2✅"
            } catch {
                error.localizedDescription
            }
        }
    }
}
let image = UIImage(named: "5.jpg")!
image.detectBarcodes { barcodes in
    for barcode in barcodes {
        let a = barcode.payloadStringValue
    }
}
发布评论

评论列表(0)

  1. 暂无评论