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 |2 Answers
Reset to default 1Short 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
}
}
let c = "error here"
withprint(error)
so you can see the actual error. – HangarRash Commented Feb 18 at 1:19