-2
DispatchSourceを使用して記録されたオーディオ(録画と再生がうまく機能する)のタイマーを実装していて、タイマーが機能します。アプリがクラッシュします。問題なく次の画面に進むことができます。 エラー:スレッド1:EXC_BAD_INSTRUCTION(コード= EXC_I386_INVOP、サブコード= 0x0)戻るボタンを押したときにDispatchSource.makeTimerSourceがクラッシュするSwift
誰かが私にこの理由を教えてください。
私のビューコントローラコード:
import Foundation
import UIKit
import AVFoundation
class RecordGreetingController: UIViewController {
@IBOutlet weak var timeLabel: UILabel!
var audioPlayer: AVAudioPlayer!
var updateTimer = DispatchSource.makeTimerSource(flags: [], queue: DispatchQueue.main)
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func toggleRecordButton(_ sender: UIButton) {
if AudioRecorderManager.shared.recorder == nil {
if AudioRecorderManager.shared.recordAudio(fileName: "NewRecording") {
updateTimer.resume()
}
let formatter = DateComponentsFormatter()
formatter.zeroFormattingBehavior = .pad
formatter.includesApproximationPhrase = false
formatter.allowedUnits = [.minute, .second]
formatter.calendar = Calendar.current
updateTimer.schedule(deadline: DispatchTime.now(), repeating: DispatchTimeInterval.milliseconds(100))
updateTimer.setEventHandler { [weak self] in
self?.timeLabel.text = formatter.string(from: AudioRecorderManager.shared.recorder!.currentTime)
}
}
else {
AudioRecorderManager.shared.finishRecording()
AudioRecorderManager.shared.recorder = nil
updateTimer.suspend()
}
}
}
マイAudioRecorderManagerクラス:
import Foundation
import AVFoundation
class AudioRecorderManager: NSObject, AVAudioRecorderDelegate {
static let shared = AudioRecorderManager()
var recordingSession: AVAudioSession!
var recorder: AVAudioRecorder?
func setup() {
recordingSession = AVAudioSession.sharedInstance()
do {
try recordingSession.setCategory(AVAudioSessionCategoryPlayAndRecord, with: .defaultToSpeaker)
try recordingSession.setActive(true)
// Request permission from user
recordingSession.requestRecordPermission{ (allowed) in
if allowed {
print("Mic authorised")
}
else {
print("Mic not authorised")
// TODO display alert to allow microphone access in settings to operate
}
}
}
catch {
print("Failed to set category", error.localizedDescription)
}
}
var meterTimer: Timer?
var recorderApc0: Float? = 0
var recorderPeak0: Float? = 0
// Starts the recording session
func recordAudio(fileName:String) -> Bool {
let url = getUserPath().appendingPathComponent(fileName+".m4a")
let audioURL = URL.init(fileURLWithPath: url.path)
let recordSettings: [String: Any] = [
AVFormatIDKey: NSNumber(value: kAudioFormatAppleLossless),
AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue,
AVEncoderBitRateKey: 12000.0,
AVNumberOfChannelsKey: 1,
AVSampleRateKey: 44100.0
]
do {
recorder = try AVAudioRecorder(url: audioURL, settings: recordSettings)
recorder?.delegate = self
recorder?.isMeteringEnabled = true
recorder?.prepareToRecord()
recorder?.record()
self.meterTimer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true, block: { (timer: Timer) in
// Update recorder meter values
if let recorder = self.recorder {
recorder.updateMeters()
self.recorderApc0 = recorder.averagePower(forChannel: 0)
self.recorderPeak0 = recorder.peakPower(forChannel: 0)
}
})
print("Recording")
return true
}
catch {
print("Error recording")
return false
}
}
// Stop recording
func finishRecording() {
self.recorder?.stop()
self.meterTimer?.invalidate()
}
// Gets path for the folder the file is being saved to
func getUserPath() -> URL {
return FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
}
func audioRecorderDidFinishRecording(_ recorder: AVAudioRecorder, successfully flag: Bool) {
print("Audio Manager did finish recording", flag)
}
func audioRecorderEncodeErrorDidOccur(_ recorder: AVAudioRecorder, error: Error?) {
print("Error encoding ", error?.localizedDescription ?? "")
}
}
無関係に、それが従うのは難しいしながら、あなたがあなたの前にタイマーを再開することができ、実行のパスがありますように、それが見えます:問題が解決しなかった上記の二つのうちの一つから下不満票を無視ハンドラとスケジュールを設定してください... – Rob
こんにちは、私は、toggleRecordButton IBActionブロックの先頭にupdateTimer.resume()を持っています。ハンドラとスケジュールの前にタイマーを再開するのが間違っているとお考えですか? – elarcoiris
はい、私はあなたがそれを始める前にあなたがタイマーを設定するべきであることを示唆しています。あなたがそれを構成し終える前にそれを始めるなら、それが何をすると思いますか?あなたが幸運なら、何も間違っていますが、なぜこの文書化されていない行動に頼っていますか?起動する前に設定を完了するのが一番安全です。 – Rob