前几天在给游戏做收尾测试时,发现了一个关于内存泄露的问题,一直没找着问题所在,经过反复调试和查找资料今天终于解决了,特此记录下来以免以后再犯!
关于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: ,否则有可能产生内存泄露,而且这种内存泄露很难发现,因为它并不违反任何规则,所以一定要注意!
分享到:
相关推荐
ios demo,performSelector和respondsToSelector,动态添加方法,多参数调用
swift并没有提供performSelector ,我伪代码写了一个扩展类。使用时请小心。详见我博文说明。http://blog.csdn.net/fengsh998/article/details/35842441
OC-performSelector
本文列举了四种延时执行某函数的方法及其一些区别。假如延时1秒时间执行下面的方法。 - (void)delayMethod { NSLog(@execute); } 1.performSelector方法 这是iOS中常用的一种延迟执行方法. //不带参数 [self ...
NSInvocation的作用和performSelector:withObject:的作用是一样的:用于iOS编程中调用某个对象的消息。 performSelector:withObject:调用一些参数较少的消息是比较方便的,但是对于参数个数大于2的消息,使用...
[self performSelector:@selector(machineBallAction) withObject:nil afterDelay:0]; 3.实现随机数:srandom(time(NULL)); 4. #pragma mark - #pragma mark Initialization 它们告诉Xcode编译器,要在...
实现延时方法执行,可用的方法有定时器、GCD、NSThread、performSelector方法
[self performSelector:@selector(lazyButtontouchDown) withObject:nil afterDelay:self.minimumPressDuration]; } -(void)lazyButtontouchDown { } //当离开按钮的时候取消所调用的方法 - (void)...
大家应该都有所了解,在 iOS中可以直接调用某个对象的消息方式有两种:一种是performSelector:withObject;再一种就是NSInvocation。 第一种方式比较简单,能完成简单的调用。但是对于>2个的参数或者有返回值的处理...
[keyWindow performSelector:@selector(startIndicatingTouches)];通过在应用程序委托的 -applicationWillResignActive: 方法末尾调用以下代码来停用触摸指示器也是一个好主意。 UIWindow *keyWindow = [[UI
//判断两个字符串是否相等,不能使用==,使用等号是判断两个对象是否是一个对象,也就是是否是一个内存地址。 //判断字符串的内容是否相同应该使用nsstring的isEqualToString:方法 //在低版本的时候,如果直接点击...
主要是iOS的绘图和动画,本来想用系统自带动画实现呢,发现实现不了,用了其他办法延时并重绘视图没有成功,用了gcd延时,nsthread休眠,performselector delay 都不行。最后用了一个定时器实现类似效果,总感觉不太...
IOS 关于取消延迟执行函数的种种。performSelector与cancelPreviousPerformRequestsWithTarget
objective c 消息 objc_msgSend 及 performSelector 的使用例子。
performSelector: 想要延迟调用某个方法: [self performSelector:@selector(delay) withObject:nil afterDelay:3.0]; 取消延迟的方法: [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@...
1.performSelector(NSObject)方法 2.NSTimer方法 3.GCD方法 4.sleep(NSThread)方法 一、performSelector方法: 代码如下:[self performSelector:@selector(delayMethod) withObject:nil afterDelay:1.0f]; 1....
1.performSelector(NSObject)方法 2.NSTimer方法 3.GCD方法 4.sleep(NSThread)方法 延迟执行代码: - (void)delayDo : (id)sender { NSLog(@do:%@,sender); } 1.performSelector(NSObject)方法 这是iOS中常用...
[(NSObject*)self performSelector:@selector(request:didUpdateStatus:) withObject:self withObject:status]; 应该是 [(NSObject*)self.delegate performSelector:@selector(request:didUpdateStatus:) with...
通过performSelector、NSTimer、sleep、GCD四种方法实现了延迟加载;可以根据自己情况选择使用那种延迟方法
[self performSelector:@selector(toggle:) withObject:btCont afterDelay:1.0f] ; #endif } #if TARGET_IPHONE_SIMULATOR #else - (void)toggle:(id)btCont { BOOL currentState = [btCont enabled] ; [btCont ...