func detect(image: CIImage) {
guard let model = try? VNCoreMLModel(for: Inceptionv3().model) else {
fatalError("Loading CoreML Model failed.")
}
let request = VNCoreMLRequest(model: model) { (request, error) in
guard let results = request.results as? [VNClassificationObservation] else {
fatalError("Model failed to process image")
}
print(results)
}
print("First")
let handler = VNImageRequestHandler(ciImage: image)
do {
print("Second")
try handler.perform([request])
print("Third")
} catch {
print(error)
}
}
In this example, what gets printed in console is:
First, Second, "Results", Third
So my question is, why does this code work even though handler.perform function is not inside the request completion handler?
This seems different to NodeJS where the data in "request" variable is not ready when it reaches handler.perform.
perform
will:
The function returns after all requests have either completed or failed.
Since the requests are completed before it returns, it is synchronous. The completion handler you passed to VNCoreMLRequest
will be called before perform
returns. Its return value also indicates whether all the requests have succeeded. If it returns before all the requests have completed, how does it know whether all of them have succeeed? :D
Because of perform
's synchronous nature, you should run it on another dispatch queue, so as to not block the main queue, like Apple did in all their sample code (1, 2):
DispatchQueue.global(qos: .userInitiated).async {
do {
try imageRequestHandler.perform(requests)
} catch let error as NSError {
print("Failed to perform image request: \(error)")
self.presentAlert("Image Request Failed", error: error)
return
}
}
Remember to switch back to the main queue when you are in the completion handler.