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

字典中ECClient对象过度释放引发EXC_BAD_ACCESS错误的解决方法

解决ECClient过度释放/僵尸对象崩溃问题

从你的代码和NSZombie崩溃日志来看,核心问题是ECClient对象被释放后仍有代码(大概率是异步回调或block)尝试访问它,或者多持有者的引用计数管理不当导致重复释放风险。下面是针对性的修复方案:

1. 明确对象所有权,避免重复强引用

你的代码里ECClient同时被ECRoom(publishClient属性、p2pClients字典)和ECSignalingChannel(signalingDelegate)持有,需要明确所有权边界:

  • ECRoom作为ECClient的创建者和生命周期管理者,保持强持有(比如publishClient用strong属性,p2pClients用强引用字典),负责对象的创建和销毁时机。
  • 将ECSignalingChannel的signalingDelegate改为弱引用(声明为weak id<ECSignalingChannelDelegate> signalingDelegate;),因为它只需要接收回调,不需要拥有对象所有权。这能避免双强引用导致的引用计数异常,也能防止循环引用。

2. 清理异步回调/block中的引用

崩溃日志显示问题出在ECClient.m:245的block销毁逻辑中,说明ECClient内部的block可能捕获了强引用的self,导致对象释放后block仍在执行,访问僵尸对象。修复方法:

  • 在ECClient的dealloc中主动取消所有未完成的异步任务、WebRTC回调,终止所有可能触发后续访问的操作,比如关闭PeerConnection、移除监听者。
  • 使用block时,用弱引用捕获self,并在block内部先判断对象是否存活:
    __weak typeof(self) weakSelf = self;
    someAsyncCallback = ^{
        __strong typeof(weakSelf) strongSelf = weakSelf;
        if (!strongSelf) return;
        // 后续操作使用strongSelf访问对象
    };
    

3. 统一管理ECClient的生命周期

当不再需要ECClient时(比如流停止发布、P2P连接断开),需要做完整的清理:

  • 从ECRoom的p2pClients字典中移除对应实例,避免字典强持有导致对象无法释放。
  • 通知ECSignalingChannel清除对应代理引用,防止后续回调触发。
  • 显式将publishClient等属性置为nil,触发ARC的引用计数递减。

示例代码:

// ECRoom.m 停止发布的方法
- (void)stopPublish {
    [_signalingChannel clearSignalingDelegate:self.publishClient];
    self.publishClient = nil;
}

// ECRoom.m 移除P2P客户端的方法
- (void)removeP2PClientWithPeerSocketId:(NSString *)peerSocketId {
    ECClient *client = [p2pClients objectForKey:peerSocketId];
    [_signalingChannel clearSignalingDelegate:client];
    [p2pClients removeObjectForKey:peerSocketId];
}

4. 规范ECClient的dealloc实现

确保ECClient的dealloc方法中彻底清理资源,避免触发异步回调:

// ECClient.m
- (void)dealloc {
    // 关闭WebRTC连接
    if (_peerConnection) {
        [_peerConnection close];
        _peerConnection = nil;
    }
    // 清空代理,切断回调链
    self.delegate = nil;
    // 取消所有未完成的异步任务
    [_pendingOperations cancelAllOperations];
    NSLog(@"ECClient dealloc: %p", self);
}

5. 跟踪对象生命周期(可选)

如果问题仍未解决,可以在ECClient的init和dealloc中添加日志,跟踪对象的创建和释放时机,确认是否存在创建/释放不匹配的情况:

- (instancetype)initWithDelegate:(id<ECClientDelegate>)delegate ... {
    self = [super init];
    if (self) {
        NSLog(@"ECClient created: %p", self);
        // 其他初始化逻辑
    }
    return self;
}

通过以上步骤,应该能解决ECClient的过度释放和僵尸对象崩溃问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 06:29:20