递归块==内存不足无声崩溃

时间:2012-06-13 02:48:54

标签: objective-c ios ios5 automatic-ref-counting objective-c-blocks

我正在使用带有ARC的iOS5中的Block来播放AVAudioPlayer音频录制的永无止境的循环。我在收到AVAudioPlayerDidFinishRecording消息后分配一个新的AVAudioPlayer,它启动一个递归循环。播放120个左右的音频剪辑后,我的应用程序始终崩溃。我可以看到它在加载每个音频文件时占用了越来越多的内存,但从不释放内存。

我正在使用单个AVAudioPlayer属性,所以每次分配新播放器时,我都希望ARC能够清理旧实例。

  1. 这些街区能否以某种方式导致旧的AVAudioPlayers停留?

  2. 使用观察者监控播放器并启动/分配新玩家会更好吗?

  3. 非常感谢你的帮助!

    -(void)playNextAudioItem{
        //get ready to load audio doc from iCloud
        NSURL *ubiquitousContainer = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
        if(ubiquitousContainer){
            //query iCloud
            query = [[NSMetadataQuery alloc]init];
            [query setSearchScopes:[NSArray arrayWithObject:NSMetadataQueryUbiquitousDocumentsScope]];
            NSPredicate *pred = [NSPredicate predicateWithFormat:@"(%K == %@)", NSMetadataItemFSNameKey, [NSString stringWithFormat:@"%@.caf", audioItemGUID]];
            [query setPredicate:pred];
            [[NSNotificationCenter defaultCenter] addObserverForName:NSMetadataQueryDidFinishGatheringNotification object:query queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif){
                //iCloud query finished gathering data
                [query disableUpdates];
                [[NSNotificationCenter defaultCenter] removeObserver:self name:NSMetadataQueryDidFinishGatheringNotification object:query];
                NSMetadataItem *item1 = [query resultAtIndex:0];
                audioCurrentVerse = [[audioDoc alloc] initWithFileURL:[item1 valueForAttribute:NSMetadataItemURLKey]];
                //open the audio file
                [audioCurrentVerse openWithCompletionHandler:^(BOOL success) {
                    if(success){
                        //configure the session and play the audio file
                        AVAudioSession *audioSession = [AVAudioSession sharedInstance];        
                        [audioSession setActive:YES error:nil];
                        NSError *error = nil;
                        [audioSession setCategory:AVAudioSessionCategoryPlayback error:nil];
                        audioPlayer = [[AVAudioPlayer alloc] initWithData:audioCurrentVerse.data error:&error];
                        audioPlayer.numberOfLoops = 0;
                        audioPlayer.delegate = self;
                        if([audioPlayer prepareToPlay]){
                            [audioPlayer play];
                        }
                    }
                }];
                [query stopQuery];
                query = nil;
            }];
            [query startQuery];
        }
    }
    
    -(void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag{
        //get an identifier for the next audio item
        audioItemIndex++;
        if(audioItemIndex >= rsAudioItems.recordCount){
            verseIndex = 0;
        }
        audioItemGUID = [rsAudioItems getRow:audioItemIndex andColumnNamed:@"audioItemGUID"];
        //recursive call to play the next audio item
        NSLog([NSString stringWithFormat:@"%d", playCount++]);
        [self playNextAudioItem];
    }
    

1 个答案:

答案 0 :(得分:1)

块获取在释放块之前未释放的堆栈的快照。不要使用递归块(或者根本没有使用递归块,如果它在这种情况下没有意义),因为块永远不会被释放,因此快照永远存在。

使用for循环可以缓解此问题。您可以将它们添加到串行调度队列中,然后在执行后释放它们。