objective-c - 递归 block ==内存不足无声崩溃

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

我在 iOS5 中使用 Blocks 和 ARC 来通过 AVAudioPlayer 播放永无休止的录音循环。我在收到AVAudioPlayerDidFinishRecording消息后分配一个新的AVAudioPlayer,这开始了一个递归循环。我的应用程序在播放 120 个左右的音频剪辑后始终崩溃。我可以看到,随着每个音频文件的加载,它消耗了越来越多的内存,但从未释放内存。

我使用的是单个 AVAudioPlayer 属性,因此我希望每次分配新播放器时 ARC 都会清理旧实例。

  1. 这些 block 是否会以某种方式导致旧的 AVAudioPlayers 保留下来?

  2. 使用观察者来监视玩家并启动/分配新玩家会更好吗?

非常感谢您的帮助!

-(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];
}

最佳答案

block 会拍摄堆栈的快照,直到释放该 block 后才会释放该快照。不要使用递归 block (或者根本不使用递归,如果它在这种情况下没有真正意义),因为这些 block 永远不会被释放,因此快照永远保留。

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

关于objective-c - 递归 block ==内存不足无声崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11007601/

相关文章:

iOS - 由于未捕获的异常 'NSInvalidArgumentException' 而终止应用程序

iphone - 如何在 ios 中使用 Graph API 识别消息已成功发布?

ios - 应用程序在按钮上崩溃 Click Action iOS

iphone - iOS 上的实时视频清理

iphone - 为 NavigationBar 中的编辑按钮设置 IBAction

ios - 如何在警报 Controller 的文本字段中使用数字键盘 [swift]

crash - iOS5-崩溃日志中的KERN_INVALID_ADDRESS

ios - 设备如何在CoreBluetooth中配对?

objective-c - 关于iOS5 SDK中自动引用计数的一些问题

c++ - 调用 [[NSBundle mainBundle] bundlePath] 时是否有生成相同字符串的 CoreFoundation 等效项?