记录传 self 给 c++ 代码时计数器加 1 的 bug

来源:互联网 发布:跑步计时器软件 编辑:程序博客网 时间:2024/06/05 09:52

遇到一个很奇怪的问题,记录一下。

问题描述:

在酷群接口提供类 KuQunPlayer (ARC的)里提供这样一个接口播放酷群语音,KuQunPlayer 类持有 KGVoicePlayer (MRC 的)类的实例 _voicePlayer ;

在每次播放群语音的时候会判断 _voicePlayer 变量是否存在,存在的话就设置为 nil ,然后再次创建一个临时的 _voicePlayer 变量,很奇怪的是在把 _voicePlayer  置为 nil 的时候,并不会调用到 KGVoicePlayer 的 dealloc 函数,导致内存泄漏。


分析问题:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{        [_playLock lock];        if (_voicePlayer) {            [_voicePlayer stop];            _voicePlayer = nil;        }         _voicePlayer = [[KGVoicePlayer alloc] init];        NSInteger code = [_voicePlayer setStream:streamBase userData:nil andType:type];                if(code != 0){            NSLog(@"set stream error!");        }        [_voicePlayer play];        [_playLock unlock];    });

没有调用到 dealloc 函数的话,_voicePlayer 的引用计数器必然就没有减少到 0,查找了代码,唯一有增加 _voicePlayer 引用计数的是在其初始化的时候计数器会被置为 1,那么也仅仅是 1 而已啊,在下次播放语音的时候会判断到上一个 _voicePlayer 不为空,然后把它置为 nil (置为nil 的话只是计数器减 1 而已,本身还是存在的,在 dealloc 里才会被销毁),正常来说现在的计数器应该为 0 了。然而却没有,问题出在 init 方法里面。

_voicePlayer = [[KGVoicePlayer alloc] init];

查找问题:

查看了一下 init 方法返回后 _voicePlayer 持有的计数器,竟然是 2 ,什么鬼?继续进入 init 函数看看

-(id)init{    self = [super init];    if (self) {                _cavplayer = new AudioPlayer::Player();        _cavPlayerCallBack = new OCAVPlayerBaseCallBack(self);        .....    }    return self;}

Debug 到 _cavPlayerCallBack = new OCAVPlayerBaseCallBack(self); 这句的时候莫名其妙的看到了 _voicePlayer 的计数器已经是 2 了,继续进入 OCAVPlayerBaseCallBack 类看看,

#import <Foundation/Foundation.h>#include "KPlayer/PlayerBase.h"@protocol OCAVPlayerBaseCallBackDelegate<NSObject>@required-(void)PlayerStatusChange:(KPlayer::PlayerBase *)player status:(KPlayer::PlayStatus )ps;@endclass OCAVPlayerBaseCallBack : public KPlayer::PlayerBaseDelegate{public:    OCAVPlayerBaseCallBack(NSObject<OCAVPlayerBaseCallBackDelegate> *delegate){        _delegate = delegate;    }    void PlayerStatusChange(KPlayer::PlayerBase *player,const KPlayer::PlayStatus &ps)    {        [_delegate PlayerStatusChange:player status:ps];    }private:    NSObject<OCAVPlayerBaseCallBackDelegate> *_delegate;};

额,只是简单的赋值而已。想不明白为什么会 +1 ,好吧,找 Google ,关键字 object-c pass param to c++,auto reference counting,

找到如下资料:

Consumed Parameters

Attribute 'ns_consumes_self'(Clang-specific)


摘录了一下关键的字段:




解决问题:

刚好,这是我想要的,在把 self 传进去之后会 retain 持有该变量,在出了作用域之后 release 掉,交出该变量的所有权,这样的话就不会导致在调用了 OCAVPlayerBaseCallBack(self) 这个之后计数器 +1 ,在 init 完后返回的就变为 2 的这种情况出现了。

最终的解决办法是修改 

OCAVPlayerBaseCallBack(NSObject<OCAVPlayerBaseCallBackDelegate> *delegate) 

为这个

OCAVPlayerBaseCallBack(__attribute((ns_consumed)) NSObject<OCAVPlayerBaseCallBackDelegate> *delegate) 

即可。

测试:

通过 debug 打印计数器发现一切正常,搞定。


0 0
原创粉丝点击