Swift开发:如何在另一个类中访问ViewController的类函数并获取结果?
解决方案:跨控制器复用CoreML图像检测逻辑
刚接触Swift遇到这种跨控制器调用函数、获取结果的问题太正常了,我给你两种实用的思路,推荐第一种,能让代码更整洁易维护~
方案一:把检测逻辑封装成独立工具类(最推荐)
原代码里的detect函数绑在ViewController里,导致其他控制器没法直接复用,而且直接修改当前控制器的imageLabel,耦合性太高。我们可以把图像检测的核心逻辑抽成一个独立的工具类,这样任何控制器都能调用它并拿到结果:
1. 创建图像分类工具类
新建一个名为ImageClassifier的Swift文件,写入以下代码:
import CoreML import Vision class ImageClassifier { // 静态方法,不需要创建实例就能调用 static func classify(image: CIImage, completion: @escaping (String?) -> Void) { guard let model = try? VNCoreMLModel(for: Resnet50().model) else { fatalError("加载CoreML模型失败") } let request = VNCoreMLRequest(model: model) { request, error in guard let results = request.results as? [VNClassificationObservation] else { print("模型处理图像失败") completion(nil) return } // 通过闭包返回最匹配的分类标识符 completion(results.first?.identifier) } let handler = VNImageRequestHandler(ciImage: image) do { try handler.perform([request]) } catch { print("检测出错:\(error)") completion(nil) } } }
2. 在ViewController中调用工具类
修改原ViewController里的代码,用工具类代替原来的detect函数:
// 比如在你需要检测图像的地方调用 ImageClassifier.classify(image: yourCIImage) { identifier in // 在主线程更新UI(保险起见,避免线程问题) DispatchQueue.main.async { self.imageLabel.text = identifier } }
3. 在SecondViewController中调用并处理结果
现在你可以直接在SecondViewController里调用工具类,拿到结果后执行你的判断逻辑:
// 假设你已经有了要检测的CIImage实例 ImageClassifier.classify(image: targetCIImage) { identifier in DispatchQueue.main.async { guard let identifier = identifier else { self.infoLabel.text = "无法识别图像" return } if identifier == "flowers" { self.infoLabel.text = "info about flowers" } else { self.infoLabel.text = "未知物体" } } }
方案二:修改原detect函数,用闭包返回结果(不推荐,耦合性高)
如果你暂时不想抽工具类,也可以修改ViewController里的detect函数,让它通过闭包把结果传递出去,然后在SecondViewController里持有ViewController的实例来调用:
1. 修改ViewController的detect函数
func detect(image: CIImage, completion: @escaping (String?) -> Void) { guard let model = try? VNCoreMLModel(for: Resnet50().model) else { fatalError("Loading CoreML Model Failed.") } let request = VNCoreMLRequest(model: model) { (request, error) in guard let result = request.results as? [VNClassificationObservation] else { print("Model failed to process image.") completion(nil) return } let identifier = result.first?.identifier self.imageLabel.text = identifier // 通过闭包把结果传出去 completion(identifier) } let handler = VNImageRequestHandler(ciImage: image) do { try handler.perform([request]) } catch { print(error) completion(nil) } }
2. 在SecondViewController中调用
需要确保你能拿到ViewController的实例(比如通过导航栈获取、或者初始化时传入):
// 假设你已经获取到了ViewController的实例,比如从导航栈取出 if let viewController = navigationController?.viewControllers.first as? ViewController { viewController.detect(image: targetCIImage) { identifier in DispatchQueue.main.async { guard let identifier = identifier else { return } if identifier == "flowers" { self.infoLabel.text = "info about flowers" } } } }
注意:这种方式会让两个控制器耦合在一起,后续代码扩展或维护会比较麻烦,所以更推荐第一种工具类的方案~
内容的提问来源于stack exchange,提问作者Jaime Miranda Ramirez
相关产品推荐
相关产品推荐

