记录传 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 打印计数器发现一切正常,搞定。
- 记录传 self 给 c++ 代码时计数器加 1 的 bug
- 记录代码合并时产生的bug
- C/C++bug记录
- c代码的记录
- [Obj-C笔记] "self = [super init]"的解释与潜藏bug
- [Obj-C笔记] "self = [super init]"的解释与潜藏bug
- [Obj-C笔记] "self = [super init]"的解释与潜藏bug
- Objective-C中[self self]的含义
- 记录一些奇妙的bug【1】
- 记录偶的bug
- 偶现bug的记录
- 修改的bug记录
- spring的bug记录
- Objective-C的self.用法
- Objective-C 【self的用法】
- ccms bug记录1
- 小bug记录1
- bug记录1
- 第十一周项目训练8.3 圆,圆柱类族的设计
- Android引导蒙层,安卓新手引导图,引导图层,支持椭圆,圆形,矩形多种形状,一行代码快速搞定
- [数据结构]10.2实现binary search tree的查找和插入操作,用非递归的方法实现
- JavaScript学习--Item31 值得你挑战的JavaScript面试题(45题)
- Mysql 存储引擎中InnoDB与Myisam的主要区别
- 记录传 self 给 c++ 代码时计数器加 1 的 bug
- HDU 2516取石子游戏(巴什博弈)
- [数据结构]10.4实现avl Tree的插入和删除操作。
- 初学单例模式
- 说说mvc模式的原理,它在android中的运用
- 6-7 8255 控制交通灯
- 【java进阶】初探泛型
- hbase1.1.3 启动一
- CodeForces 671A Recycling Bottles