问题描述
好的,我已经为此工作了好几天,并且在这里和其他地方搜索了大量似乎无法解决该问题的帖子。我有一个使用带有textView和record按钮的自定义单元格的应用程序:
在单元格的自定义类中,是设置记录器和播放器的地方,就像这样:
import UIKit
import RealmSwift
import AVFoundation
class newNoteTableViewCell: UITableViewCell,UITextViewDelegate,AVAudioPlayerDelegate,AVAudioRecorderDelegate {
let realm = try! Realm()
@IBOutlet weak var lyricsField: UITextView!
@IBOutlet weak var recordButton: UIButton!
var recorder = AVAudioRecorder()
var player = AVAudioPlayer()
var fileName: String? {
didSet {
audioFileURL = getDocumentDirectory().appendingPathComponent(fileName!)
}
}
var audioFileURL: URL? {
didSet {
setupRecorder()
}
}
override func didMoveToSuperview() {
super.didMoveToSuperview()
// make sure scroll is disabled
lyricsField.isScrollEnabled = false
}
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool,animated: Bool) {
super.setSelected(selected,animated: animated)
}
//MARK: - AVAudioRecorder and Player Delegate Methods
@IBAction func recordButtonPressed(_ sender: UIButton) {
if recordButton.currentImage == UIImage(systemName: "record.circle") {
recorder.record()
recordButton.setImage(UIImage(systemName: "record.circle.fill"),for: .normal)
} else if recordButton.currentImage == UIImage(systemName: "record.circle.fill") {
recorder.stop()
recordButton.setImage(UIImage(systemName: "play.circle"),for: .normal)
} else if recordButton.currentImage == UIImage(systemName: "play.circle") {
setupPlayer()
player.play()
recordButton.setImage(UIImage(systemName: "stop.circle.fill"),for: .normal)
} else {
player.stop()
recordButton.setImage(UIImage(systemName: "play.circle"),for: .normal)
}
}
func getDocumentDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory,in: .userDomainMask)
return paths[0]
}
func setupRecorder() {
let audioSession = AVAudioSession.sharedInstance()
do {
try audioSession.setCategory(AVAudioSession.Category.playAndRecord,options: [.defaultToSpeaker])
} catch let error as NSError {
print(error.description)
}
let recordSettings = [AVFormatIDKey : kAudioFormatAppleLossless,AVEncoderAudioQualityKey : AVAudioQuality.max.rawValue,AVEncoderBitRateKey : 320000,AVNumberOfChannelsKey : 2,AVSampleRateKey : 44100.0] as [String : Any]
do {
recorder = try AVAudioRecorder(url: self.audioFileURL!,settings: recordSettings)
recorder.delegate = self
recorder.prepareToRecord()
} catch {
print(error)
}
}
func audioRecorderDidFinishRecording(_ recorder: AVAudioRecorder,successfully flag: Bool) {
recordButton.setImage(UIImage(systemName: "play.circle"),for: .normal)
print(recorder.url.absoluteString)
//A new Recording object is created to store the fileName and audioFileURL
let newRecording = Recording()
if let safeFileName = fileName {
newRecording.audioFileName = safeFileName
newRecording.urlString = recorder.url.absoluteString
//The Recording is then added to realm
do {
try realm.write {
realm.add(newRecording)
print("New recording added to Realm")
}
} catch {
print("Error when adding new Recording to realm: \(error)")
}
}
}
func setupPlayer() {
if let safeURL = audioFileURL {
do {
player = try AVAudioPlayer(contentsOf: safeURL)
print("Player set up to use the cell's audio URL")
player.delegate = self
player.prepareToPlay()
player.volume = 1.0
} catch {
print(error)
}
}
}
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer,for: .normal)
}
}
在视图控制器中,每当加载单元时,都会为其分配一个唯一的fileName,该文件名随后触发fileName的didSet并依次分配该单元的audioFileURL。设置的audioFileURL然后触发使用该audioFileURL设置记录器。记录器完成记录后,audioFileURL的fileName和absoluteString都将保存到自定义Recording对象中的Realm中:
import Foundation
import RealmSwift
class Recording: Object {
@objc dynamic var audioFileName: String = ""
@objc dynamic var urlString: String = ""
}
所有这些记录然后被提取并存储在视图控制器上的“记录”列表中。如果单元格的fileName作为记录的audioFileName之一出现在记录列表中,则将该记录的urlString分配给单元格的audioFileURL:
if let safeRecordings = recordings {
if safeRecordings.contains(where: {$0.audioFileName == cell.fileName}) {
print("A corresponding recording is present")
cell.recordButton.setImage(UIImage(systemName: "play.circle"),for: .normal)
if let recordingForCell = safeRecordings.filter("urlString CONTAINS[cd] %@",cell.fileName!).first {
print(recordingForCell.urlString)
cell.audioFileURL = URL(string: recordingForCell.urlString)
}
}
}
(上面的代码来自视图控制器的cellForRowAt)
尽管事实上,所有这些代码似乎都可以正常工作(URL被存储,然后重新分配给它们各自的单元格),每当我在录制了一些音频后离开视图控制器然后返回以希望能够播放,出现此错误:
2020-10-03 13:05:12.082532-0500 topline[3877:1221774] OpenFromDataSource failed
2020-10-03 13:05:12.084646-0500 topline[3877:1221774] Open failed
Error Domain=NSOSStatusErrorDomain Code=1685348671 "(null)"
我搜索了错误,发现它是kAudioFileInvalidFileError,但我不明白为什么会收到此错误。其他人在这里询问有关此错误的问题时,被告知他们需要将文件类型从.m4a更改为其他类似.aif的文件。我尝试将文件名更改为以.aif结尾,并且没有区别。其他人则说,他们仅在使用模拟器时才收到此错误,但我在模拟器和物理设备上却收到了此错误。同样,在第一次录制音频之后,录制的回放确实开始工作。仅当离开视图并返回希望能够访问为其创建的URL的音频时,才会出现该错误。我还看到人们建议在导入AVFoundation的下面初始化AVAudioPlayer(),这样它是一个全局变量,但这也不起作用。请帮助!
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)