【问题标题】:How do I save and fetch audio data to/from CoreData with Objective-C?如何使用 Objective-C 在 CoreData 中保存和获取音频数据?
【发布时间】:2017-04-28 18:59:17
【问题描述】:

我是 iOS 开发新手。

如何使用 Objective-C 将音频数据保存到 CoreData 或从 CoreData 获取音频数据?

我只知道我必须使用 NSData 和二进制数据。

【问题讨论】:

  • 避免将大文件(音频)存储到 Core Data。更喜欢保存参考(文件名、URL...)。如果您仍然想这样做并且遇到问题,请发布您尝试过的内容以及问题所在。
  • 使用NSData 和二进制属性就是你的做法。具体有什么不明白的?

标签: ios objective-c xcode core-data


【解决方案1】:

正如@shallowThought 在他的评论中所说,您通常不应该在 Core Data 中存储大的二进制数据对象。将声音文件保存到应用程序的文档目录或其他沙箱目录之一,然后在 Core Data 中存储文件的 URL 或路径。

【讨论】:

  • 如果我需要录制新的音频?我应该将这个音频文件存储在哪里?
  • 我实际上已经完成了将音频、视频和图像指定为二进制数据类型属性并使用该属性的允许外部存储。当您检查生成的文件时,CoreData 会创建所需的目录和文件,并管理创建和监督存储的过程。这对于包含超过 100MB 数据的 200 多个媒体文件的集合来说效果很好。我将手动方法用于其他更复杂的情况,例如存储数百到数千张构成地图平铺叠加层的图像,它确实有效,但是您拥有复杂性。
【解决方案2】:

我想我会添加我用来完成我在上面评论中描述的代码。这是在 swift 3.0(不是 ObjC,抱歉)中使用 CoreData 存储音频记录(以及图像和视频,尽管这些捕获更复杂,此处未显示)。

我发现最好将记录捕获到文件中,然后将其转换为我存储到数据库中的 NSData 值,再次作为带有允许外部存储选项的二进制数据类型,CoreData 可以这样做。

流程是首先调用 setupAudio() 来创建单例音频会话,然后使用连接到 UI 上的按钮的 startRecordAction() 和 stopRecordAction() 方法来驱动会话(因此使用 sharedInstance 表示法)。虽然它看起来像多个会话,但它只是一个共享单例,这种结构让我可以在方法之间分解使用该实例的进程。

我已经对此进行了简化,所以这里的 stop 方法会在录音停止时自动将录音添加到数据库中。免责声明:我已经删掉了一堆不适用于您的问题的代码,所以我可能添加了一个错误或删除了一些必需的东西,但我认为它已经接近了。

代码如下:

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...
    }
}

希望对您有所帮助...

【讨论】:

    猜你喜欢
    • 2013-06-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多