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

Time:12-05

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()
    }
}

CodePudding user response:

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()}
    }
}

CodePudding user response:

Without code I'm just guessing what is your setup.

One way to fix this issue would be to store the startTime and stopTime values in the AudioRecorder class itself, instead of just using them locally within the startRecording() and stopRecording() functions. This way, the values will still be available when the saveToCoreData() function is called.

For example, you could add two properties to the AudioRecorder class to store the startTime and stopTime values:

class AudioRecorder {
    var startTime: Date?
    var stopTime: Date?

    func startRecording() {
        self.startTime = Date()
        // other code here...
    }

    func stopRecording() {
        self.stopTime = Date()
        // other code here...
    }

    func saveToCoreData(rating: Int) {
        // use self.startTime and self.stopTime here...
        // other code here...
    }
}

Alternatively, you could pass the startTime and stopTime values as arguments to the saveToCoreData() function, so that the view can provide these values when calling the function. This would look something like this:

class AudioRecorder {
     func startRecording() -> Date {
        return Date()
        // other code here...
    }

    func stopRecording() -> Date {
        return Date()
        // other code here...
    }

    func saveToCoreData(startTime: Date, stopTime: Date, rating: Int) {
        // use startTime and stopTime here...
        // other code here...
    }
}

In this case, the view would need to store the startTime and stopTime values returned by the startRecording() and stopRecording() functions, and then pass these values to the saveToCoreData() function when calling it.

I hope this helps!

  • Related