如何向VNCoreMLRequest传递UILabel参数以实现多请求结果分标签输出
The core issue here is that your current classificationRequest is a static, lazily initialized instance—you can't dynamically pass different UILabel instances to it when running multiple requests. The fix is to create a new VNCoreMLRequest instance each time you need to perform a classification, which lets you bind the specific label directly to the request's completion handler.
Here's how to adjust your code step by step:
1. Remove the Static classificationRequest Property
First, get rid of that lazy initialized request since we'll create a new one per classification:
// Delete this entire block // lazy var classificationRequest: VNCoreMLRequest = { ... }()
2. Modify updateClassifications to Create a Request Per Call
In your updateClassifications method, create the VNCoreMLRequest on the fly, and capture the incoming label parameter in the completion handler. We'll also add weak references to avoid memory leaks:
func updateClassifications(for image: UIImage, label: UILabel) { label.text = "Classifying..." let orientation = CGImagePropertyOrientation(rawValue: UInt32(image.imageOrientation.rawValue))! guard let ciImage = CIImage(image: image) else { fatalError("Unable to create \(CIImage.self) from \(image).") } DispatchQueue.global(qos: .userInitiated).async { // Create the model and request here, right before performing the classification do { let model = try VNCoreMLModel(for: Test().model) let request = VNCoreMLRequest(model: model) { [weak self, weak label] request, error in guard let self = self, let label = label else { return } self.processClassifications(for: request, error: error, label: label) } request.imageCropAndScaleOption = .centerCrop let handler = VNImageRequestHandler(ciImage: ciImage, orientation: orientation) try handler.perform([request]) } catch { print("Failed to perform classification.\n\(error.localizedDescription)") // Update the label on main thread if something goes wrong DispatchQueue.main.async { label.text = "Classification failed" } } } }
3. Adjust processClassifications to Use the Passed Label
Your existing processClassifications method is already set up to accept the label—just make sure you use it instead of the hardcoded OutputOne:
func processClassifications(for request: VNRequest, error: Error?, label: UILabel) { DispatchQueue.main.async { guard let results = request.results else { label.text = "Unable to classify image.\n\(error!.localizedDescription)" return } // Example: Cast results to VNClassificationObservation and update the label if let classifications = results as? [VNClassificationObservation] { let topClassification = classifications.first label.text = topClassification?.identifier ?? "No classification result" } } }
Why This Works
- Dynamic Parameter Binding: By creating a new
VNCoreMLRequesteach time, you can capture the specificUILabelinstance for that classification task directly in the completion handler. - No Static State: You avoid the problem of a single request instance trying to handle multiple labels at once.
- Memory Safety: Using
[weak self, weak label]ensures you don't create strong reference cycles, especially since UI elements like labels are often held by view controllers.
Now you can call updateClassifications with different labels, and each classification result will be sent to the correct UI element.
内容的提问来源于stack exchange,提问作者Noah Cristino

