這裏是上下文: 我一直在開發音頻相關的應用程序一段時間了,我有點碰壁,不知道下一步該怎麼做。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'。 –