kiertron
kiertron

Reputation: 21

constant 'error' used before being initialized

I am detecting microphone blow and using this to trigger an animation and am getting this error message. "constant 'error' used before being intialised". This is the code I have:

    override func viewDidLoad() {
    super.viewDidLoad()

    //make an AudioSession, set it to PlayAndRecord and make it active
    let audioSession:AVAudioSession = AVAudioSession.sharedInstance()
    try! audioSession.setCategory(AVAudioSessionCategoryRecord)
    try! audioSession.setActive(true)

    //set up the URL for the audio file
    let documents: AnyObject = NSSearchPathForDirectoriesInDomains( FileManager.SearchPathDirectory.documentDirectory,  FileManager.SearchPathDomainMask.userDomainMask, true)[0] as AnyObject
    let str = (documents as! NSString).appending("recordTest.caf")
    NSURL.fileURL(withPath: str as String)


    // make a dictionary to hold the recording settings so we can instantiate our AVAudioRecorder
    let recordSettings: [NSObject : AnyObject] = [AVFormatIDKey as NSObject:kAudioFormatAppleIMA4 as AnyObject,
                                                  AVSampleRateKey as NSObject:44100.0 as AnyObject,
                                                  AVNumberOfChannelsKey as NSObject:2 as AnyObject,AVEncoderBitRateKey as NSObject:12800 as AnyObject,
                                                  AVLinearPCMBitDepthKey as NSObject:16 as AnyObject,
                                                  AVEncoderAudioQualityKey as NSObject:AVAudioQuality.max.rawValue as AnyObject

    ]

    //declare a variable to store the returned error if we have a problem instantiating our AVAudioRecorder
    let error: NSError?

    //Instantiate an AVAudioRecorder
    recorder = try! AVAudioRecorder(url: documents as! URL, settings: recordSettings as! [String : Any])

    //If there's an error, print it - otherwise, run prepareToRecord and meteringEnabled to turn on metering (must be run in that order)
    if let e = error {
        print(e.localizedDescription)
    } else {
        recorder.prepareToRecord()
        recorder.isMeteringEnabled = true

        //start recording
        recorder.record()

        //instantiate a timer to be called with whatever frequency we want to grab metering values
        self.levelTimer = Timer.scheduledTimer(timeInterval: 0.02, target: self, selector: #selector(ViewController.levelTimerCallback), userInfo: nil, repeats: true)

    }

}

//selector/function is called every time our timer (levelTime) fires
func levelTimerCallback() {
    //update meters
    recorder.updateMeters()

    //print to the console if we are beyond a threshold value
    if recorder.averagePower(forChannel: 0) > -7 {
        print("Mic Blow Detected ")
        print(recorder.averagePower(forChannel: 0))
        isAnimating = false
    } else {
        isAnimating = true
    }
}

It also seems that this line is forcing the app to quit so obviously this is where the issue is but I am new to Xcode and cannot spot what I have done wrong, if anyone has ideas on what I should change this too that would be great.

recorder = try! AVAudioRecorder(url: documents as! URL, settings: recordSettings as! [String : Any])

Thanks in advance!

Upvotes: 0

Views: 3310

Answers (1)

Scott Thompson
Scott Thompson

Reputation: 23711

You have no code that could have set the value of error between the point that it is declared and the point that it is used. For error possibly take on a new value, it would have to be passed to the constructor for the AVAudioRecorder. You could initialize the error with:

let error : Error? = nil

But again this would be frivolous because there is no chance for it's value to change (it is a let variable) and even if it were a var, it is not passed to any code between when it is declared and when it is used in the if let construction.

You are crashing because you have told the system that you want to create the AVAudioRecorder but it should never fail (that's try!). More likely you want to do something like:

let documentSearchPaths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let documentsDir = documentSearchPaths[0] as NSString
let recordingFilePath = documentsDir.appendingPathComponent("recordTest.caf")
let recordingFileURL = NSURL.fileURL(withPath: recordingFilePath)

var recorder : AVAudioRecorder?
do{
    let audioSession = AVAudioSession.sharedInstance()
    try audioSession.setCategory(AVAudioSessionCategoryRecord)
    try audioSession.setActive(true)

    // make a dictionary to hold the recording settings so we can instantiate our AVAudioRecorder
    let recordSettings: [String : Any] = [AVFormatIDKey : kAudioFormatAppleIMA4,
                                          AVSampleRateKey : NSNumber(value: 44100.0),
                                          AVNumberOfChannelsKey : NSNumber(value: 2),
                                          AVEncoderBitRateKey : NSNumber(value: 12800),
                                          AVLinearPCMBitDepthKey : NSNumber(value: 16),
                                          AVEncoderAudioQualityKey :NSNumber(value: AVAudioQuality.max.rawValue)
    ]

    recorder = try AVAudioRecorder(url: recordingFileURL, settings: recordSettings)
} catch let audio_error as NSError {
    print("Setting up the audio recording failed with error \(audio_error)")
}

if let recorder = recorder {
    recorder.prepareToRecord()
    recorder.isMeteringEnabled = true

    //start recording
    recorder.record()

    //etc...
}

Upvotes: 2

Related Questions