前几天在给游戏做收尾测试时,发现了一个关于内存泄露的问题,一直没找着问题所在,经过反复调试和查找资料今天终于解决了,特此记录下来以免以后再犯!

关于objective-c的内存管理,我们都知道一个原则就是“谁创建,谁释放”,换句话说,不是我们创建的,就不用我们去释放。但是实际上objective-c的内存管理远远没那么简单,我的情况是这样的:

我在debug模式下面用CCLOG在dealloc函数里面输出一些信息,目的就是要检查场景的dealloc方法在replaceScene的时候有没有被调用,按照子龙山人大哥的说法,如果场景切换的时候dealloc没有调用,说明你这个场景的内存有问题。有可能被某个对象retain了,其retainCount在replaceScene的时候没有减少到0,所以dealloc方法是不会调用的。如果dealloc方法都没有调掉,那么这其实就是一种内存泄露。我在检查时,发现一个场景死活不调用dealloc,最后恨不得把所有的游戏逻辑都移除了,还是不走dealloc。

最后的最后才发现实际上是performSelector延时调用的问题,经查找资料,performSelector关于内存管理的执行原理是这样的执行 [self performSelector:@selector(method1:) withObject:self.tableLayer afterDelay:3]; 的时候,系统会将tableLayer的引用计数加1,执行完这个方法时,还会将tableLayer的引用计数减1,而在我的游戏里这个延时执行函数是被多次调用的,有时切换场景时延时函数已经被调用但还没有执行,这时tableLayer的引用计数没有减少到0,也就导致了切换场景dealloc方法没有被调用,出现了内存泄露。

所以最后我的解决办法就是取消那些还没有来得及执行的延时函数,代码很简单:

[NSObject cancelPreviousPerformRequestsWithTarget:self]

当然你也可以一个一个得这样用:

[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(method1:) object:nil]

加上了这个以后,切换场景也就很顺利地执行了dealloc方法,至此问题解决!

最后在找资料时也发现了,延时调用实现长按钮的实现思路,记录下来以备后用:

在touchBegan里面

[self performSelector:@selector(longPressMethod:) withObject:nil afterDelay:longPressTime]

然后在end 或cancel里做判断,如果时间不够长按的时间调用:

[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(longPressMethod:) object:nil]

取消began里的方法

最后最后总结:

performSelector是一个很有用的函数,跟它打过不少交道,经过血与泪的教训,总结一下它的使用如下:

使用前先检测一下,

SEL testSelector = @selector(test:);

if([tester respondsToSelector:testSelector])

{

//如果响应就执行

[tester test:@"invoke test method"];

}

使用后,如果有必要,需要显示的调用cancelPreviousPerformRequestsWithTarget:selector:object: ,否则有可能产生内存泄露,而且这种内存泄露很难发现,因为它并不违反任何规则,所以一定要注意!

延时调用的时候要注意相关推荐

  1. swift 多线程GCD和延时调用

    GCD 是一种非常方便的使用多线程的方式.通过使用 GCD,我们可以在确保尽量简单的语法的前提下进行灵活的多线程编程.在 "复杂必死" 的多线程编程中,保持简单就是避免错误的金科玉 ...

  2. 一个class运用promise的延时调用

    使用prosmise链式调用可以实现延时调用的效果 class Person {constructor(name){this.name = name;this.queue = Promise.reso ...

  3. 60-300-024-使用-延迟数据-Flink中延时调用设计与实现

    1.世界 2.概述 在电商商品购买过程中有这样一些场景:用户点击下单,此时订单处于待支付状态,如果在2小时之后还处于待支付状态那么就将这笔订单取消,置为取消状态:用户收货之后可以对商品进行评价,如果在 ...

  4. js定时器和延时调用的使用

    javascript定时器使用 可以使用setInterval(回调函数,间隔时间)函数,定时调用一段程序 回调函数本质就是一个函数(有点废话),但它是JS帮我们调用的,所以叫回调函数. 间隔时长单位 ...

  5. Swift - GCD 和延时调用

    GCD 是一种非常方便的使用多线程的方式.通过使用GCD,我们可以在确保语法尽量简单的前提下进行灵活的多线程编程.在"复杂必死"的多线程编程中,保持简单就是避免错误的金科玉律.好消 ...

  6. JS中定时器和延时调用学习笔记

    JS中定时器和延时调用 在JS中希望一个函数重复的执行,可以为该函数设置一个定时装置 方法: setInterval(); 该方法可以将一个函数,每隔一段时间被调用一次 有两个参数 第一个是回调函数, ...

  7. js延时调用和定时调用

    知识点: 延时调用:一个函数不马上执行,而是隔一段时间在执行,而且只会执行一次 延时调用和定时调用的区别,定时调用会执行多次,而延时调用只会执行一次 详细代码: <!DOCTYPE html&g ...

  8. JS中的延时调用(setTimeout()、clearTimeout())

    延时调用 setTimeout(),不会立即执行函数,会隔一段时间在调用函数. var timer = setTimeout(function(){},5000);//在5秒之后调用函数 clearT ...

  9. 西门子博图的FB块_西门子S7-1200,如何在FB块中使用操作定时器?|定时器|timer|延时|调用|plc...

    在上一篇文章介绍了S7-1200 PLC的定时器,以及介绍了S7-1200 PLC与S7-200/200 SMART PLC的定时器的分类的不同及区别. S7-1200 PLC的定时器一共有四种类型, ...

  10. onDestroy 延时10s调用

    导致activity onDestroy 延时10s调用 同事在自定义view onDraw中调用 硬件加速setLayerType(View.LAYER_TYPE_SOFTWARE, mPaint) ...

最新文章

  1. Linux内存管理 (26)内存相关工具
  2. Linux服务器---流量监控bandwidthd
  3. android 获取连接WiFi的名称
  4. SQL Server 2005两本教程案例数据库
  5. vmware配置centos7网络
  6. 与php有区别_php://output和php://stdout的区别
  7. 分析:重定向和请求转发
  8. java取整数位_java获取整数的各位数值
  9. VS2010编译驱动程序
  10. QtCreator格式化代码---Beautifier插件使用方式
  11. dbf文件mysql,dbf文件怎么打开?dbf是什么文件?
  12. 32bit还是64bit
  13. Fabric 1.0的多机部署
  14. java中常用的json转换工具类
  15. 基本函数依赖和候选键_给定一组字母表示的函数依赖集,怎样确定候选键?
  16. @【 ENVI】“应用程序无法正常启动0x0000007b”问题
  17. UE4_Stereo Panoramic Movie Capture_合并左右眼为一张图片
  18. vue使用LayIM组件接入第三方通讯平台:融云
  19. WITNESS高级教程
  20. [转][汇编] 汇编语言实现简易文本编辑器(光标移动、上卷和退格删除)

热门文章

  1. 微信爱帮公交查询之公交线路查询
  2. 深度学习神经网络训练调参技巧
  3. android 图片编辑工具,照片编辑器:Photo Editor
  4. java课设迷宫游戏_Java课程设计走迷宫.doc
  5. DM、PQ、PM、diskgen分区工具介绍比较
  6. CM311-1_YST_S905L3(B)_安卓9.0_设置无密码_默认打开adb_完美AI语音_线刷固件包
  7. xHCI1.1-TRB Ring
  8. java罗盘说明_综合罗盘各层应用说明
  9. 标准盒子模型简单讲解
  10. 干货 | 互联网平台资金结算的合规处理方案