I have a very simple update method, where I've included the debugging lines.
@IBOutlet weak var meterLabel: UILabel!
func updateMeter(string: String)
{
if Thread.isMainThread {
meterLabel.text = string
} else {
DispatchQueue.main.sync {
meterLabel.text = string
}
}
print(string)
}
Obviously string
is never nil. The function updateMeter
is called about 3 times a second, however currently in the simulator I do not see the UILabel change (it does change during calls to this same updateMeter
elsewhere). Is there any reason why changing a UILabel's text would not have a visible result on the main thread?
Called here:
public func startRecording()
{
let recordingPeriod = TimeInterval(Float(Constants.windowSize)/Float(Constants.sampleFrequency))
var index = 0
Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true) { timer in
let audioRecorder = self.AudioRecorders[index]!
audioRecorder.deleteRecording()
audioRecorder.record()
DispatchQueue.main.asyncAfter(deadline: .now() + recordingPeriod)
{
if let pitch = self.finishSampling(audioRecorder: audioRecorder, index: self.AudioRecorders.index(of: audioRecorder))
{
self.meterViewController?.updateMeter(string: String(pitch))
}
}
index = index + 1
if index == 4 { index = 0 }
if !(self.keepRecording ?? false) { timer.invalidate() }
}
}
Other methods called:
private func finishSampling(audioRecorder: AVAudioRecorder?, index: Int?) -> Float?
{
audioRecorder?.stop()
if let index = index, var (data, _, _) = loadAudioSignal(audioURL: getDirectory(for: index))
{
let pitch = getPitch(&data, Int32(data.count), Int32(Constants.windowSize), Int32(Constants.sampleFrequency))
return Float(pitch)
}
return nil
}
private func loadAudioSignal(audioURL: URL) -> (signal: [Float], rate: Double, frameCount: Int)?
{
guard
let file = try? AVAudioFile(forReading: audioURL),
let format = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: file.fileFormat.sampleRate, channels: file.fileFormat.channelCount, interleaved: false),
let buf = AVAudioPCMBuffer(pcmFormat: format, frameCapacity: UInt32(file.length))
else
{
return nil
}
try? file.read(into: buf)
let floatArray = Array(UnsafeBufferPointer(start: buf.floatChannelData?[0], count:Int(buf.frameLength)))
return (signal: floatArray, rate: file.fileFormat.sampleRate, frameCount: Int(file.length))
}
Where getPitch
does some simple processing and runs relatively quick.
By calling usleep
you are blocking the main thread. The main thread is the thread that updates the UI. Since it is blocked, it cannot do that.
You should use an alternate approach, such as a Timer
to periodically update the label.