2012-11-21 42 views
1

這是我現在使用的代碼,它不工作(當我按下調用此方法的按鈕時,沒有任何反應)。以前,我有一個audioPlayer的屬性,它工作(顯然,下面的所有audioPlayer都是self.audioPlayer)。問題是,當我試圖播放兩次聲音時,它會結束第一聲播放。AVAudioPlayer - 你必須創建一個屬性才能工作嗎? (Xcode)

這是沒有用的,因爲我在製作音板並希望聲音能夠重疊。我想我可以讓audioPlayer變成一個局部變量而不是屬性,一切都會好的,但是現在聲音根本不起作用,我不知道爲什麼。在我爲AVAudioPlayer找到的所有教程中,都有一個屬性,但沒有人解釋爲什麼。如果這不起作用,我還有什麼替代方法可以使聲音重疊?

- (void)loadSound:(NSString *)sound ofType:(NSString *)type withDelegate:(BOOL)delegate { 
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle] 
            pathForResource:sound 
            ofType:type]]; 

AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil]; 
if (delegate) audioPlayer.delegate = self; 
[audioPlayer prepareToPlay]; 

[audioPlayer play]; 
} 

回答

7

你需要一個屬性或伊娃的原因是它提供了強有力的參考。當使用ARC時,任何沒有強指針的對象都是公平的遊戲,而且事實上這就是你所看到的。

你也是正確的,一個AVAudioPlayer強指針將只允許一次引用一個音頻播放器。

如果您選擇繼續使用AVAudioPlayer的解決方案是使用某種集合對象來保存所有播放器實例的強引用。你可以使用一個NSMutableArray如下所示:

編輯我調整了代碼稍微使播放的聲音方法需要一個NSStringsoundName參數。

@synthesize audioPlayers = _audioPlayers; 
-(NSMutableArray *)audioPlayers{ 
    if (!_audioPlayers){ 
     _audioPlayers = [[NSMutableArray alloc] init]; 
    } 
    return _audioPlayers; 
} 
-(void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag{ 
    [self.audioPlayers removeObject:player]; 
} 
-(void)playSoundNamed:(NSString *)soundName{ 
    NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle] 
             pathForResource:soundName 
             ofType:@"wav"]]; 
    AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil]; 
    if (audioPlayer){ 
     [audioPlayer setDelegate:self]; 
     [audioPlayer prepareToPlay]; 
     [audioPlayer play]; 
     [self.audioPlayers addObject:audioPlayer]; 
    } 
} 

通常的AVAudioPlayer是矯枉過正一個聲音效果/音板應用。爲了快速聲「滴」,你可能會發現音頻工具箱框架,outlined in my answer to this question.

From looking at the System Sound class reference, it seems like you can only play one sound at a time.

它只能起到一個SystemSoundID在同一時間。例如,如果你有soundOne和soundTwo。當soundTwo正在播放時,您可以播放soundOne,但一次不能播放一種聲音的多個實例。

What's the best way to be able to play sounds that can overlap while still being efficient with the amount of code and memory?

最好是意見。

如果你需要兩個相同聲音同時播放的實例,那麼我會說在這個答案中發佈的代碼將是代碼使用。由於相同聲音的每個重疊實例都需要創建新資源,因此使用audioPlayerDidFinishPlaying:這樣的代碼更易於管理(內存可以很容易地被回收)。

如果相同聲音的重疊實例不是交易斷路器,那麼我認爲只需使用AudioServicesCreateSystemSoundID()來創建每個聲音的一個實例就更有效率。

我絕對不會試圖管理每個按下按鈕的創建和處理SystemSoundID s。這會匆匆出錯。在這種情況下,AVAudioPlayer僅僅是可維護性的明顯贏家。

+0

從查看System Sound類參考,看起來您一次只能播放一個聲音。能夠播放可重疊的聲音的最佳方式是什麼,而對代碼和內存的數量仍然有效? – robertfiorentino

+0

@fiorgodx我編輯了我的答案以迴應您的評論。 – NJones

+0

幫助我解決了當前正在播放的播放器的停止問題,並在啓動另一個播放器時釋放它(不停止播放按鈕)。現在,內存使用並不是天空飛揚,它只能作爲唯一一個音頻播放器的例子。謝謝 –

4

我假設你正在使用ARC。音頻播放器不起作用的原因是因爲AVAudioPlayer對象正在釋放,然後在loadSound:方法終止後隨後銷燬。這是由於ARC的對象管理而發生的。在ARC之前,代碼:

AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil]; 
if (delegate) audioPlayer.delegate = self; 
[audioPlayer prepareToPlay]; 
[audioPlayer play]; 

會按預期播放聲音。但是,在loadSound:方法終止後,AVAudioPlayer對象仍然存在。這意味着每次播放聲音時,都會泄漏內存。

一點關於

屬性被引入,以減少代碼的開發人員必須編寫和維護量的屬性。在屬性之前,開發人員必須爲每個實例變量編寫setters和getters。這是很多冗餘代碼。屬性的一個幸運的副作用是它們處理了很多爲基於對象的實例變量編寫setter/getters所需的內存管理代碼。這意味着很多開發人員開始僅使用屬性,即使對於不需要公開的變量也是如此。

由於ARC爲您處理所有的內存管理細節,因此屬性只能用於其原始目的,從而減少冗餘代碼的數量。傳統的iVars默認會被強烈引用,這意味着一個簡單的賦值,例如: title = [NSString stringWithFormat:@"hello"]; 與代碼基本相同: self.title = [NSString stringWithFormat:@"hello"];

好的,回到你的問題。

如果你打算在loadSound:方法來創建AVAudioPlayer情況下,你需要不斷的強引用每個AVAudioPlayer實例或其他ARC會破壞它。我建議將新創建的AVAudioPlayer對象添加到NSMutableArray陣列中。如果採用AVAudioPlayerDelegate協議,則可以實施audioPlayerDidFinishPlaying:successfully:方法。您可以在其中刪除陣列中的AVAudioPlayer對象,讓ARC知道可以銷燬該對象。

相關問題