[英]Swift concurrency failing on first load
I have a concurrent function running, that is connected to a UIBarbuttonItem
我有一个并发函数正在运行,它连接到UIBarbuttonItem
.init(barButtonSystemItem: .camera, target: self, action: #selector(runClassification(_:))
Although I have run into a weird issue.虽然我遇到了一个奇怪的问题。 Running any task (as simple or complex) will not run on the very first initialisation of the view controller.运行任何任务(无论是简单的还是复杂的)都不会在视图控制器的第一次初始化时运行。 Moving the code outside the Task
runs as expected.将代码移到Task
之外按预期运行。 Running the function, leaving the view, and tapping the button again will successfully disable the buttons.运行函数,离开视图,再次点击按钮将成功禁用按钮。
Print statements work but any code falls into the void.打印语句有效,但任何代码都落入了空白。 View Controller isn't constructed any differently than usual. View Controller 的构造与平常没有任何不同。
@objc func runClassification(_ sender: UIBarButtonItem) {
Task {
// This runs
navigationItem.rightBarButtonItems?.forEach { $0.isEnabled = false }
guard let image = imageView.image else { return }
do {
let response = try await MLClassifer.sharedManager.updateClassifications(capturedImage: image)
// None of this runs on first call.
print("MLClassifer.sharedManager.updateClassifications begining")
} catch {
debugPrint(error)
}
}
}
-- Update MLClassifier.swift
-- 更新MLClassifier.swift
private typealias ClassifierCheckedContinuation = CheckedContinuation<[VNRecognizedObjectObservation], Error> // 1
private var classifierContinuation: ClassifierCheckedContinuation?
@MainActor
func updateClassifications(capturedImage: UIImage) async throws -> [VNRecognizedObjectObservation] {
self.capturedImage = capturedImage
let orientation = CGImagePropertyOrientation(capturedImage.imageOrientation)
guard let ciImage = CIImage(image: capturedImage) else {
throw MLClassiferError.invalidConversion
}
guard let model = self.model else {
throw MLClassiferError.invalidModel
}
let mlModel = try VNCoreMLModel(for: model)
let handler = VNImageRequestHandler(ciImage: ciImage, orientation: orientation)
let request = VNCoreMLRequest(model: mlModel) { request, error in
self.processClassifications(for: request, error: error)
}
try handler.perform([request])
return try await withCheckedThrowingContinuation { (continuation: ClassifierCheckedContinuation) in
self.classifierContinuation = continuation
}
}
func processClassifications(for request: VNRequest, error: Error?) {
if let error = error {
classifierContinuation?.resume(throwing: error)
return
}
guard let results = request.results, !results.isEmpty else {
classifierContinuation?.resume(throwing: MLClassiferError.invalidConversion)
return
}
guard let classifications = results as? [VNRecognizedObjectObservation], !classifications.isEmpty else {
classifierContinuation?.resume(throwing: MLClassiferError.invalidConversion)
return
}
guard let image = self.capturedImage,
let capturedImage = CIImage(image: image)
else {
classifierContinuation?.resume(throwing: MLClassiferError.invalidConversion)
return
}
classifierContinuation?.resume(returning: classifications)
print("MLClassifer.sharedManager.updateClassifications returning")
}
After some more semi-sleepless nights, I found the solution.经过几个半睡不醒的夜晚,我找到了解决办法。
Rather than having it like this;而不是这样;
let request = VNCoreMLRequest(model: mlModel) { request, error in
self.processClassifications(for: request, error: error)
}
try handler.perform([request])
return try await withCheckedThrowingContinuation { (continuation: ClassifierCheckedContinuation) in
self.classifierContinuation = continuation
}
You need to have it like this: Throwing the handler.perform
inside the closure seems to have been the missing puzzle.你需要这样:在闭包内抛出handler.perform
似乎是缺少的难题。
return try await withCheckedThrowingContinuation { continuation in
self.classifierContinuation = continuation
let request = VNCoreMLRequest(model: mlModel) { request, error in
self.processClassifications(for: request, error: error)
}
try? handler.perform([request])
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.