How do I save and fetch audio data to/from CoreDat

2019-09-22 08:37发布

问题:

I'm a new to iOS development.

How can I save and fetch audio data to/from CoreData with Objective-C?

I just know that I have to use NSData and Binary Data.

回答1:

As @shallowThought says in his comment, you should generally not store big binary data objects in Core Data. Save the sound files to your app's documents directory or one of the other sandbox directories, and then store a URL or path to the file in Core Data.



回答2:

Thought I'd add the code that I use to accomplish what I describe in my comment above. This is in swift 3.0 (not ObjC, sorry) using CoreData to store audio recordings (as well as images and videos, though the captures for those are more complex and not shown here).

I found it worked best to capture the recording to a file and then convert that to an NSData value that I store into the database, again as a Binary Data type with the option to allow External Storage, which CoreData does.

The flow is to first call setupAudio() to create a singleton audio session and then use the startRecordAction() and stopRecordAction() methods that are connected to buttons on your UI to drive the session (hence the sharedInstance notation). Though it looks like multiple sessions, it's just one shared singleton and this structure lets me break up the processes using that instance among the methods.

I've simplified this so here the stop method automatically adds the audio recording to the database when the recording stops. Disclaimer: I've cut out a bunch of code that doesn't apply to your question, so I may have added a bug or dropped something that's required, but I think it's close.

Here's the code:

import AVFoundation

...

var audioRecorder:AVAudioRecorder!

let recordSettings = [AVSampleRateKey : NSNumber(value: Float(44100.0)),
                      AVFormatIDKey : NSNumber(value: Int32(kAudioFormatMPEG4AAC)),
                      AVNumberOfChannelsKey : NSNumber(value: 1),
                      AVEncoderAudioQualityKey : NSNumber(value: Int32(AVAudioQuality.medium.rawValue))]

func directoryURL() -> URL {
    let fileManager = FileManager.default
    let urls = fileManager.urls(for: .documentDirectory, in: .userDomainMask)  
    let documentDirectory = urls[0] as NSURL
    let soundURL = documentDirectory.appendingPathComponent(“capturedAudio.m4a")
    return soundURL!
}

func setupAudio()
{
    let audioSession = AVAudioSession.sharedInstance()

    do {
        unowned let myself = self
        try audioSession.setCategory(AVAudioSessionCategoryPlayAndRecord)
        try audioRecorder = AVAudioRecorder(url: myself.directoryURL(),
                                            settings: recordSettings)
        audioRecorder.prepareToRecord()
    } catch {
        logError...
    }
}

@IBAction func startRecordAction(_ sender: UIButton) {
    if !audioRecorder.isRecording {
        let audioSession = AVAudioSession.sharedInstance()
        do {
            try audioSession.setActive(true)
            audioRecorder.record()
        } catch {
            logError...
        }
    }
}

@IBAction func stopRecordAction(_ sender: UIButton) {
    audioRecorder.stop()
    let audioSession = AVAudioSession.sharedInstance()

    do {
        try audioSession.setActive(false)
    } catch {
        logError...
    }

    var audioTrack: Data?

    do {
        audioTrack = try Data(contentsOf: audioRecorder.url)
    } catch {
        logError...
    }

    addMediaCaptureToDB(audioTrack!, mediaType: "Recording")
}

func addMediaCaptureToDB(_ mediaData: Data, mediaType: String)
{
    guard let newRec = NSEntityDescription.insertNewObject(forEntityName: "MediaCapture", into: context) as? MediaCapture else
    {
        logError...
    }

    newRec.mediaCapture = mediaData as NSData  // Binary Data field / option set to allow External Storage
    newRec.type = mediaType
    newRec.captureDate = NSDate()
    newRec.uniqueID = String(Date().timeIntervalSince1970)

    // Save the new MediaCapture record to the database

    do {
        try context.save()
    } catch {
    logError...
    }
}

Hope that helps...