Search code examples
iosswiftobjectswiftuiview

How to keep an object alive while going between a class and views in swift?


I have a class named AudioRecorder and a view named RecorderView. Audiorecorder has the following functions

  • startRecording() --> Starts recording and gets recording start time.
  • stopRecording() --> Stops recording and gets recording stop time.
  • saveToCoreData() --> Saves startTime, stopTime and rating to coredata

How it works is, RecorderView lets the user to start and stop a recording by calling the functions in AudioRecorder. Once the user stops the recording, a new view named RatingView is shown. User provides a rating in RatingView and hits submit. By selecting submit, saveToCoreData in RecorderView is called with the user provided rating. The problem here is that, by the time the view calls saveToCoreData, startTime and stopTime are lost. This is why they are "nil" and only rating has a proper value. How do I keep startTime and stopTime alive for the next use? Is there a way to fix this problem?

import SwiftUI

struct RecorderView: View {
    @ObservedObject var audioRecorder: AudioRecorder
    @State private var showRatingView = false
    
    var body: some View {
        VStack {
            if audioRecorder.recording == false {
                Button(action: {self.audioRecorder.startRecording()}) {
                    Image(systemName: "circle.fill")
                }
            } else {
                Button(action: {self.audioRecorder.stopRecording(); showRatingView = true}) {
                    Image(systemName: "stop.fill")
                }
            }
            VStack {
                if showRatingView == true {
                    NavigationLink(destination: SurveyRatingView(rating: 1, audioRecorder: AudioRecorder()), isActive: self.$showRatingView) { EmptyView()}
                }
            }
        }
    }
}



struct RatingView: View {
    
    @Environment(\.managedObjectContext) var moc
    @State var rating: Int16
    @ObservedObject var audioRecorder: AudioRecorder
    
    @State private var displayNewView: Bool = false
    
    var body: some View {
        VStack {
            
            Text("How was the recording experience?")
//          RatingView(rating: $survey)
            Button(action: {
                self.audioRecorder.saveToCoreData(rating: rating)
            }) {
                Text("Submit Response")
            }
        }
        .navigationBarBackButtonHidden(true)
    }
}

This is what the class AudioRecorder looks like

class AudioRecorder:  NSObject, ObservableObject {
    @Published var startTime: Date
    @Published var stopTime: Date
    
    func startRecording() -> Date {
        self.startTime = Date()
        //Start recording related code here
    }
    
    func stopRecording() -> Date{
        // Stop recording related code here
        self.stopTime = Date()
    }
    
    
    func saveToCoreData(rating: Int16){
        let aRec = AudioRec(context: moc)
        aRec.uuid = UUID()
        aRec.startTime = self.startTime //This is nil
        aRec.stopTime = self.stopTime  //This is nil
        aRec.rating = rating  //Only this has a proper value
        
        try moc.save()
    }
}

Solution

  • In your "showRatingView" VStack you are passing a new instance of AudioRecorder. You should pass the instance you already have:

    VStack {
        if showRatingView == true {
            NavigationLink(destination: SurveyRatingView(rating: 1, audioRecorder: self.audioRecorder), isActive: self.$showRatingView) { EmptyView()}
        }
    }