繁体   English   中英

Swift 并发在第一次加载时失败

[英]Swift concurrency failing on first load

我有一个并发函数正在运行,它连接到UIBarbuttonItem

.init(barButtonSystemItem: .camera, target: self, action: #selector(runClassification(_:))

虽然我遇到了一个奇怪的问题。 运行任何任务(无论是简单的还是复杂的)都不会在视图控制器的第一次初始化时运行。 将代码移到Task之外按预期运行。 运行函数,离开视图,再次点击按钮将成功禁用按钮。

打印语句有效,但任何代码都落入了空白。 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)
        }
    }
}

-- 更新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")
}

经过几个半睡不醒的夜晚,我找到了解决办法。

而不是这样;

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
    }

你需要这样:在闭包内抛出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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM