我正在使用SKAction类别播放AVAudioPlayer声音 - 它看起来像这样:
+ (SKAction *)atw_playSoundWithData:(NSData *)soundData {
// If AVAudioSession is inactive do not make any sound
if ([BAPAppDelegate isAudioSessionActive] == NO) {
return [SKAction runBlock:^{}];
} else {
// Create playSoundAction which starts on concurrent queue to gain speed
return [SKAction runBlock:^{
NSError *error;
AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc] initWithData:soundData error:&error];
if (!error) {
audioPlayer.numberOfLoops = 0;
[audioPlayer play];
// Cache audioPlayer to avoid autoreleasing before play end
[SKAction atw_cacheAudioPlayer:audioPlayer];
}
//NSLog(@"%s Added: %@ withError: %@, Cache: %lu", __PRETTY_FUNCTION__, audioPlayer, error, (unsigned long)[sATWAudioPlayersCache count]);
} queue:sATWAudioPlayersCacheQueue];
}
}
缓存AVAudioPlayer是为了避免过早发布玩家 - 这是方法:
static NSMutableSet *sATWAudioPlayersCache; // It's our cache
static dispatch_queue_t sATWAudioPlayersCacheQueue; // It's our concurrent queue of audioPlayers that are playing
+ (void)atw_cacheAudioPlayer:(AVAudioPlayer *)audioPlayer {
// Init cache for the first time
if (sATWAudioPlayersCache == nil) {
sATWAudioPlayersCache = [[NSMutableSet alloc] initWithCapacity:1];
sATWAudioPlayersCacheQueue = dispatch_queue_create("com.AppThatWorks.SKAction+ATWSound.sATWAudioPlayersCacheQueue", DISPATCH_QUEUE_CONCURRENT);
}
if (audioPlayer == nil) return;
dispatch_barrier_async(sATWAudioPlayersCacheQueue, ^{
[sATWAudioPlayersCache addObject:audioPlayer];
});
// Set delayed cache clear event for that audioPlayer (with barrier also to ensure exclusive access)
double delay = [audioPlayer duration]+0.1; // +0.1 second buffer for safe sound end
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC));
dispatch_after(popTime, sATWAudioPlayersCacheQueue, ^(void){
dispatch_barrier_async(sATWAudioPlayersCacheQueue, ^{
// For safety sake, stop audioPlayer to avoid potential bad access while removing/autoreleasing.
// It could happen if delay was nearly equal to [audioPlayer duration] (i.e. released while stopping).
[audioPlayer stop];
[sATWAudioPlayersCache removeObject:audioPlayer];
//NSLog(@"%s Removed: %@ , Cache: %lu", __PRETTY_FUNCTION__, audioPlayer, (unsigned long)[sATWAudioPlayersCache count]);
});
});
}
我发现每秒播放大约10个声音会影响FPS从60到有时甚至49 fps(不幸的是,它非常明显),尽管CPU仍然保持在其使用率的20%。因为跳过播放声音会修复FPS性能,这就是为什么我的问题来自:
问题: SKAction runBlock如何影响FPS? (或者我的GCD解决方案/ AVAudioPlayer如何做到这一点?)