You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AVFAudio调用performSelector:withObject:finishedPlaying时崩溃排查求助

排查AVFAudio调用performSelector:withObject:finishedPlaying崩溃问题

从你给出的崩溃栈来看,崩溃发生在objc_msgSend,且处于__NSThreadPerformPerform上下文——这说明RunLoop在执行你通过performSelector提交的任务时,给一个无效对象发送了消息。这种崩溃90%以上都是野指针问题:要么接收消息的对象已经被释放,要么该对象根本不响应finishedPlaying这个方法。

下面给你一步步的排查和解决思路:

1. 优先确认:接收消息的对象是否已被提前释放?

performSelector如果是延迟执行(比如用afterDelay)或者跨线程投递任务,很容易出现目标对象在任务执行前就被销毁的情况。比如你在音频回调里调用[self performSelector:@selector(finishedPlaying:) withObject:item afterDelay:0.1],结果self在这0.1秒内被销毁,等RunLoop执行任务时,就会给已释放的对象发消息,直接触发崩溃。

排查方法:

  • 开启Xcode僵尸对象调试:在Scheme的Diagnostics面板勾选"Zombie Objects",重新运行。崩溃发生时,Xcode会明确告诉你是给哪个类的已释放对象发了消息,还能展示对象被释放的调用栈,直接定位根源。
  • 在目标对象的dealloc方法加日志:比如NSLog(@"XXX对象已释放"),如果崩溃前打印了这条日志,就实锤了对象提前释放的问题。

2. 检查方法签名与Selector拼写

有时候崩溃是因为Selector拼写错误,或者方法参数类型不匹配:

  • 你声明的方法是- (void)finishedPlaying:(AVPlayerItem *)item,但调用时用了@selector(finishedPlaying)(少了冒号);
  • 传递的参数类型和方法期望的不匹配,比如把NSString传给了需要AVPlayerItem的参数。

排查方法:

  • 用编译器校验:把@selector(finishedPlaying:)改成NSSelectorFromString(@"finishedPlaying:"),如果编译器警告找不到该方法,就是拼写或声明问题;
  • 确认方法在头文件中声明,或在@implementation里正确实现,避免因私有方法导致的Selector不识别。

3. 用Block替代PerformSelector,从根源规避问题

performSelector是较老旧的API,本身存在生命周期和类型安全隐患。现在更推荐用GCD Block替代,不仅更安全,还能清晰管理对象生命周期:

比如跨线程调用:

// 替代performSelector:withObject:onThread:
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
    typeof(self) strongSelf = weakSelf;
    if (strongSelf) {
        [strongSelf finishedPlaying:yourObject];
    }
});

比如延迟调用:

// 替代performSelector:withObject:afterDelay:
__weak typeof(self) weakSelf = self;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    typeof(self) strongSelf = weakSelf;
    if (strongSelf) {
        [strongSelf finishedPlaying:yourObject];
    }
});

Block会自动捕获对象引用,加上weakSelf+strongSelf的组合,既能避免循环引用,又能确保调用时对象仍存活,从根源杜绝野指针崩溃。

4. 注意AVFAudio回调的线程环境

AVFAudio的回调通常运行在专门的音频线程(非主线程)。如果你在这个回调里直接调用performSelector到主线程,一定要确保主线程的对象没有提前释放。另外,不要在音频线程中做UI操作——虽然这不是本次崩溃的直接原因,但也是常见的坑点。


内容的提问来源于stack exchange,提问作者ordinaryman09

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 04:18:52