iosswiftlight

Why can't I call any hardware methods in SwiftUI


I am trying to turn the torch of the iOS device on and off in my Swift app.

By looking at the documentation, I can see that lockForConfiguration(), setTorchModeOn(1.0), and unlockForConfiguration()are what I need to call.

However, these methods are apparently not in scope. My first thought was that these methods were for Objective-C, but the documentation shows that these methods are in fact, for Swift.

I am maybe calling these methods incorrectly. However, from what I see I can call these methods raw (No parent script/class).

import SwiftUI

struct ContentView: View {
    var body: some View {
        Text("Hello")
    }
    
    func turnTorchOn() {
        lockForConfiguration()
        setTorchModeOn(1.0)
        unlockForConfiguration()
    }
}
             
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

AVCaptureDevice is only for Objective-C and everything else I can find is also for Objective-C. Could someone please explain how I could do this in Swift? Thanks in advance!


Solution

  • You need an AVCaptureDevice instance to call the methods on.

    import SwiftUI
    import Combine
    import AVKit
    
    class CaptureSession: ObservableObject {
        lazy var device = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back)
    }
    
    struct ContentView: View {
        @StateObject var session = CaptureSession()
        
        var body: some View {
            Text("Hello")
                .onTapGesture {
                    turnTorchOn()
                }
        }
        
        func turnTorchOn() {
            do {
                let device = session.device
                try device?.lockForConfiguration()
                defer { device?.unlockForConfiguration() }
                try device?.setTorchModeOn(level: 1.0)
            } catch {
                print("Can't turn torch on, check device has LED flash!")
            }
        }
    }
    

    In this example, we're getting the default rear camera for the device and (assuming it has a torch) are setting that specific device to turn on when we tap the label. Because SwiftUI views can be redrawn at any point, we need to make the device lives as long as the view is on screen, so we're persisting it in a StateObject.