这里是上下文: 我一直在开发音频相关的应用程序一段时间了,我有点碰壁,不知道下一步该怎么做。iOS:在回调函数中调用setNeedDisplay时的线程问题
我最近在应用中实现了一个绘制音频输出的FFT显示的自定义类。这个类是UIView的一个子类,这意味着每次我需要绘制一个新的FFT更新时,我需要用新的样本值在我的类实例上调用setNeedDisplay
。因为我需要为每一帧绘制一个新的FFT(帧〜1024样本),这意味着我的FFT的显示函数被称为很多(1024/SampleRate = 0.02321秒)。至于样本计算,它完成了44'100 /秒。我在iOS中管理线程并不是很有经验,所以我读了一点关于它的内容,这里是我如何做到的。
它是如何完成的:我有一个NSObject“AudioEngine.h”的子类,它负责处理我应用程序中的所有DSP处理,这是我设置FFT显示的地方。所有样本值都计算并分配给dispatch_get_global_queue
块内的我的FFT子类,因为这些值需要在后台不断更新。一旦样本指标已经达到了最大帧数的setneedDisplay
方法被调用,这是一个dispatch_async(dispatch_get_main_queue)
块
内完成。在“AudioEngine.m”
for (k = 0; k < nchnls; k++) {
buffer = (SInt32 *) ioData->mBuffers[k].mData;
if (cdata->shouldMute == false) {
buffer[frame] = (SInt32) lrintf(spout[nsmps++]*coef) ;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
@autoreleasepool {
// FFT display init here as a singleton
SpectralView *specView = [SpectralView sharedInstance];
//Here is created a pointer to the "samples" property of my subclass
Float32 *specSamps = [specView samples];
//set the number of frames the FFT should take
[specView setInNumberFrames:inNumberFrames];
//scaling sample values
specSamps[frame] = (buffer[frame] * (1./coef) * 0.5);
}
});
} else {
// If output is muted
buffer[frame] = 0;
}
}
//once the number of samples has reached ksmps (vector size) we update the FFT
if (nsmps == ksmps*nchnls){
dispatch_async(dispatch_get_main_queue(), ^{
SpectralView *specView = [SpectralView sharedInstance];
[specView prepareToDraw];
[specView setNeedsDisplay];
});
什么我的问题是:
- 我得到各种线程问题,特别是在主线程上,例如
Thread 1: EXC_BAD_ACCESS (code=1, address=0xf00000c)
,有时在应用程序启动时会调用viewDidLoad,而且每当我尝试与w进行交互时ith任何UI对象。 - 即使在FFT显示屏上,UI响应速度也变得异常缓慢。
我认为这个问题是:这肯定是关系到一个线程问题,因为你可能知道,但我对这个话题确实没有经验。我想可能会强制主线程上的任何UI显示更新,以解决我所遇到的问题,但又一次;我甚至不知道如何正确地做到这一点。
任何输入/洞察将是一个巨大的帮助。 在此先感谢!
什么的线程上面的代码运行吗? _我想可能会强制主线程上的任何UI显示更新,以解决我的问题,但又一次;我甚至不知道如何正确地做到这一点。所有的UIKit调用都必须在主线程中进行,并且您可以通过调用带有主队列的'dispatch_async()'从另一个线程执行此操作,就像您在上面的最后一行代码。你不应该从'dispatch_get_global_queue()'队列中调用UIKit调用(这是为了并发执行)。 – Mark
你确定你的'SpectralView'单例是线程安全的吗? 'sharedInstance'方法应该使用'dispatch_once',并确保你从后台调用的方法不会以任何方式更新UI。您还应该确保从多个线程调用的任何属性都能正确序列化。 – Hamish
@ originaluser2真的很好点。我甚至没有注意到我没有在我的视图中使用'dispatch_once'。 –