In my application, there are 5 different tabs in the tab bar. One of them is the camera tab. When you click it, the custom camera I made opens. However, when you switch to the camera tab from one of the other tabs, it takes too long to open the camera. How can I solve this?
Tab view
struct ContentView: View {
@State private var selectedTab: Tab = .Home
var body: some View {
VStack(spacing: 0) {
switch selectedTab {
case .Camera:
PhotoView()
.transition(.identity)
case .Records:
Color.gray
.transition(.identity)
case .Home:
HomeView()
.transition(.identity)
case .Test:
Color.cyan
.transition(.identity)
case .Settings:
SettingsView()
.transition(.identity)
}
CustomTabBar(selectedTab: $selectedTab)
}
}
}
Camera view and model
struct PhotoView: View {
@ObservedObject var camera = CameraModel()
var body: some View {
ZStack {
GeometryReader { proxy in
let size = proxy.size
CameraPreview(camera: camera, size: size)
}
VStack {
if camera.isTaken {
HStack {
Spacer()
Button {
camera.reTake()
} label: {
Image(systemName: "arrow.triangle.2.circlepath.camera")
.foregroundStyle(.black)
.padding()
.background(.white)
.clipShape(Circle())
.padding(.trailing, 10)
.padding(.top, 10)
}
}
}
Spacer()
HStack {
if camera.isTaken {
Button {
if !camera.isSaved {
camera.savePic()
}
} label: {
Text(camera.isSaved ? "Saved" : "Save")
.foregroundStyle(.black)
.fontWeight(.semibold)
.padding(.vertical, 10)
.padding(.horizontal, 20)
.background(.white)
.clipShape(Capsule())
.padding(.leading)
.padding(.bottom, 10)
}
Spacer()
} else {
Button {
camera.takePic()
} label: {
ZStack {
Circle()
.fill(.white)
.frame(width: 65, height: 65)
Circle()
.stroke(.white, lineWidth: 2)
.frame(width: 70, height: 70)
}
.padding(.bottom, 10)
}
}
}
}
}
.onAppear {
camera.Check()
}
}
}
class CameraModel: NSObject, ObservableObject, AVCapturePhotoCaptureDelegate {
@Published var isTaken = false
var session = AVCaptureSession()
var alert = false
var output = AVCapturePhotoOutput()
var preview : AVCaptureVideoPreviewLayer!
@Published var isSaved = false
var picData = Data(count: 0)
func Check() {
switch AVCaptureDevice.authorizationStatus(for: .video) {
case .authorized:
setUp()
return
case .notDetermined:
AVCaptureDevice.requestAccess(for: .video) { (status) in
if status {
self.setUp()
}
}
case .denied:
self.alert.toggle()
return
default:
return
}
}
func setUp() {
do {
self.session.beginConfiguration()
let device = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back)
let input = try AVCaptureDeviceInput(device: device!)
if self.session.canAddInput(input) {
self.session.addInput(input)
}
if self.session.canAddOutput(self.output) {
self.session.addOutput(self.output)
}
self.session.commitConfiguration()
} catch {
print(error.localizedDescription)
}
}
func takePic() {
DispatchQueue.global(qos: .background).async {
self.output.capturePhoto(with: AVCapturePhotoSettings(), delegate: self)
DispatchQueue.main.async {
withAnimation {
self.isTaken.toggle()
}
}
}
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
self.session.stopRunning()
}
}
func reTake() {
DispatchQueue.global(qos: .background).async {
self.session.startRunning()
DispatchQueue.main.async {
withAnimation {
self.isTaken.toggle()
}
self.isSaved = false
}
}
}
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
if error != nil {
return
}
print("pic taken..")
guard let imageData = photo.fileDataRepresentation() else {
print("Fotoğraf verisi alınamadı.")
return
}
self.picData = imageData
}
func savePic() {
print(self.picData)
let image = UIImage(data: self.picData)!
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
self.isSaved = true
print("saved successfully..")
}
}
struct CameraPreview: UIViewRepresentable {
@ObservedObject var camera: CameraModel
var size: CGSize
func makeUIView(context: Context) -> UIView {
let view = UIView()
camera.preview = AVCaptureVideoPreviewLayer(session: camera.session)
camera.preview.frame.size = size
camera.preview.videoGravity = .resizeAspectFill
view.layer.addSublayer(camera.preview)
camera.session.startRunning()
return view
}
func updateUIView(_ uiView: UIViewType, context: Context) {
}
}