How to structure code to handle mutations from Vision (face detection) requests

Hi Fellow devs, This is only nominally related to the Vision SDK. I want to detect faces and update my UI based on the results.

The code below does not compile. The line that begins with let request = throws the following error: Escaping closure captures mutating 'self' parameter

I understand the problem with trying to modify a struct from within a closure, but I don't know what I'd need to change to be able to update the UI, based on the results from the face detection request.

Any suggestions? thanks, in advance

import SwiftUI
import Vision

struct ContentView: View {

    @State var uiImage = UIImage(named: "Ollie")!
    @State var faceCount = 0

    init() {
        let handler = VNImageRequestHandler(cgImage: uiImage.cgImage!, options: [:])
        let request = VNDetectFaceRectanglesRequest { _, _ in
            self.faceCount = 3
        }
        try! handler.perform([request])
    }

    var body: some View {
        VStack {
            Image(uiImage: uiImage)
                .resizable()
                .aspectRatio(contentMode: .fit)
            Text("faces: \(faceCount)")
        }
        .padding()
    }
}
Answered by MobileTen in 749808022

Replace mrbean with another image in the assets folder.


import SwiftUI

@main
struct DevForumVisionApp: App {
    @StateObject var model = VisionModel()
    var body: some Scene {
        WindowGroup {
            ContentView()
                .environmentObject(model)
        }
    }
}
import SwiftUI
import Vision

struct ContentView: View {
    
    @EnvironmentObject private var model: VisionModel
    
    var body: some View {
        VStack {
            Image(uiImage: model.uiImage)
                .resizable()
                .aspectRatio(contentMode: .fit)
            Text("faces: \(model.faceCount)")
        }
        .onAppear(perform: {
            model.run()
        })
        .padding()
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
            .environmentObject(VisionModel())
    }
}
class VisionModel: ObservableObject {
    @Published private(set) var uiImage = UIImage(named: "mrbean")!
    @Published private(set) var faceCount: Int = 0

    private(set) var request: VNDetectFaceRectanglesRequest?
    private(set) var handler: VNImageRequestHandler?
    private(set) var requestOptions = [VNImageOption: Any]()
    
    init() {
    }
    
    func run() {
        handler = VNImageRequestHandler(cgImage: uiImage.cgImage!, options: requestOptions)
        self.request = VNDetectFaceRectanglesRequest() { [weak self] request, error in
            if error == nil, let count = request.results?.count {
                self?.faceCount = count
            }
        }
        if let request, let handler {
            do {
                try handler.perform([request])
            } catch {
                print(error)
            }
        }
    }
}
Accepted Answer

Replace mrbean with another image in the assets folder.


import SwiftUI

@main
struct DevForumVisionApp: App {
    @StateObject var model = VisionModel()
    var body: some Scene {
        WindowGroup {
            ContentView()
                .environmentObject(model)
        }
    }
}
import SwiftUI
import Vision

struct ContentView: View {
    
    @EnvironmentObject private var model: VisionModel
    
    var body: some View {
        VStack {
            Image(uiImage: model.uiImage)
                .resizable()
                .aspectRatio(contentMode: .fit)
            Text("faces: \(model.faceCount)")
        }
        .onAppear(perform: {
            model.run()
        })
        .padding()
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
            .environmentObject(VisionModel())
    }
}
class VisionModel: ObservableObject {
    @Published private(set) var uiImage = UIImage(named: "mrbean")!
    @Published private(set) var faceCount: Int = 0

    private(set) var request: VNDetectFaceRectanglesRequest?
    private(set) var handler: VNImageRequestHandler?
    private(set) var requestOptions = [VNImageOption: Any]()
    
    init() {
    }
    
    func run() {
        handler = VNImageRequestHandler(cgImage: uiImage.cgImage!, options: requestOptions)
        self.request = VNDetectFaceRectanglesRequest() { [weak self] request, error in
            if error == nil, let count = request.results?.count {
                self?.faceCount = count
            }
        }
        if let request, let handler {
            do {
                try handler.perform([request])
            } catch {
                print(error)
            }
        }
    }
}
How to structure code to handle mutations from Vision (face detection) requests
 
 
Q