请教个performselector 取消延时执行的问题问题

- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)
这个方法是单线程的,也就是说只有当前调用次方法的函数执行完毕后,selector方法才会被调用。
- (void)changeText:(NSString *)string
& & label.text =
& & NSLog(@&changeText:(NSString *)string&);
- (void)changePopoverSize
& & [self performSelector:@selector(changeText:) withObject:@&Happy aha& afterDelay:1];
& & NSLog(@&changePopoverSize#####end&);
& & sleep(5);
& & NSLog(@&changePopoverSize-----end&);
执行结果(注意时间):
17:14:06.697 awrbv[] changePopoverSize#####end
17:14:11.698 awrbv[] changePopoverSize-----end
17:14:11.701 awrbv[] changeText:(NSString *)string
如果要想多线程的话,可以是使用
- (void)performSelectorInBackground:(SEL)aSelector withObject:(id)arg
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)
代码如下:
- (void)changeText:(NSString *)string
& & label.text =
& & NSLog(@&changeText:(NSString *)string&);
- (void)changePopoverSize
& & [self performSelectorOnMainThread:@selector(changeText:) withObject:@&Happy aha111& waitUntilDone:YES];
& & NSLog(@&changePopoverSize#####end&);
& & sleep(5);
& & NSLog(@&changePopoverSize-----end&);
执行结果如下:
17:19:29.618 awrbv[] changeText:(NSString *)string
17:19:29.619 awrbv[] changePopoverSize#####end
17:19:34.620 awrbv[] changePopoverSize-----end
可以看出,如果waitUntilDone:YES那么等changeText执行完毕后再往下执行
如果waitUntilDone:NO的话,结果如下:
17:21:12.135 awrbv[] changePopoverSize#####end
17:21:17.137 awrbv[] changePopoverSize-----end
17:21:17.139 awrbv[] changeText:(NSString *)string
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:461005次
积分:4899
积分:4899
排名:第3490名
原创:38篇
转载:260篇
评论:28条
(14)(2)(3)(2)(2)(1)(1)(9)(1)(8)(21)(15)(6)(3)(2)(10)(5)(6)(6)(3)(3)(6)(3)(6)(16)(7)(12)(5)(1)(1)(3)(3)(6)(5)(1)(1)(11)(4)(5)(2)(5)(3)(11)(10)(4)(1)(10)(19)(6)(1)(2)(1)(2)(1)performSelector afterDelay在子线程上调用不运行 - 简书
下载简书移动应用
写了1819字,被8人关注,获得了7个喜欢
performSelector afterDelay在子线程上调用不运行
平时我们想延迟一段代码的运行,最简单的方法就是使用 performSelector afterDelay,但是你有没有发现在子线程中调用这个方法,有时候延时执行的代码并没有走,这是为什么呢?我们先看一下下面的例子:我们在.m文件里面加入如下方法
- (void)viewDidLoad {
[super viewDidLoad];
NSThread * thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadRun) object:nil];
[thread start];}
- (void)threadRun{
[self performSelector:@selector(delayTest) withObject:nil afterDelay:0.2];
//不会调用
[self performSelector:@selector(noDelayTest) withObject:nil];
//会调用}- (void)delayTest{
NSLog(@"this is delayTest");}- (void)noDelayTest{
NSLog(@"this is noDelayTest");}
我们发现,在0.2秒之后,delayTest方法并没有走,而如果我们没有使用afterDelay的noDelayTest 方法却直接调用了,这是为什么呢?其实performSelector 方法相当于告诉当前线程去直接去调用noDelayTest方法,noDelayTest方法当然会被调用,而performSelector afterDelay 相当于 告诉当前线程 用当前线程的定时器去调用delayTest方法,但是我们知道,在子线程中,默认是没有定时器的,所以delayTest方法将没有被调用的机会.解决办法使用dispatch_after代替performSelector afterDelay,具体如下- (void)threadRun{
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 0.2*NSEC_PER_SEC);
dispatch_after(time, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self delayTest];
});}结论 1.performSelector 如果不使用延时,程序会再子线程上直接调用该方法,方法会被调用 2.如果使用延时,在子线程中方法不会被调用,因为该方法等待定时器去调用,而该子线程中没有定时器,所以不会调用 3.解决2的方法就是使用dispatch_after里面会有一个定时器,来调用方法
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮
被以下专题收入,发现更多相似内容:
简书程序员大本营
投稿须知:
1.本专题仅收录与程序有关的文章。
2.请在代码框里写代码,尽量保证可看性。
关注简书官...
· 83359人关注
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
选择支付方式:[self performSelector:@selector(fun:) withObject:obj afterDelay:2.0];步骤是可以在未执行前_四大备份MySql数据库方法及可能遇到的有关问题_多线程程序一段有关问题代码分析(生产者消费者)__脚本百事通
稍等,加载中……
^_^请注意,有可能下面的2篇文章才是您想要的内容:
[self performSelector:@selector(fun:) withObject:obj afterDelay:2.0];步骤是可以在未执行前
四大备份MySql数据库方法及可能遇到的有关问题
多线程程序一段有关问题代码分析(生产者消费者)
[self performSelector:@selector(fun:) withObject:obj afterDelay:2.0];步骤是可以在未执行前
[self performSelector:@selector(fun:) withObject:obj afterDelay:2.0];方法是可以在未执行前
在一个函数里面执行了延时间执行某个方法的时候
[self performSelector:@selector(fun:) withObject:obj afterDelay:2.0];
所以最后我的解决办法就是取消那些还没有来得及执行的延时函数,代码很简单:
[NSObject cancelPreviousPerformRequestsWithTarget:self]
当然你也可以一个一个得这样用:
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(method1:) object:nil]
加上了这个以后,切换场景也就很顺利地执行了dealloc方法,至此问题解决!
四大备份MySql数据库方法及可能遇到的有关问题
四大备份MySql数据库方法及可能遇到的问题
一:通过备份王等软件进行备份前台进不去?
用备份王等软件进行备份是大多老站长的选择,这种方法方便快捷,只要上传备份软件到空间一步步操作就可以,但是许多刚接触备份王软件的客用户来说还原后会出现一个问题:因为新老空间数据库用户名和密码不统一,网站文件打包过来后因没有修改连接文件,还原数据库是好了,可是前台会提示数据库连接错误,网站从而出现打不开的情况。
解决方法:学会修改网站配置文件,大多是由config和data.php文件来控制,将这些文件中的连接信息设置为正确的连接信息,避免网站不能打开。
二:通过phpmyadmin备份你会发现还原很麻烦
许多站长觉得,mysql数据库是通过phpmyadmin在进行管理,用phpmyadmin进行备份总该很安全吧?于是兴冲冲的进入phpmyadmin,也不管导出选择的是txt,还是rar格式,也不管是不是要分段备份,全部操作一次,这样总会很安全吧?可是一到还原就会傻了眼,原来通过phpmyadmin导出的备份文件还只能通过phpmyadmin软件还原回去,而此时大家会发现这个软件最大只允许还原小于2M的备份来源,麻烦了吧?想破脑袋也找不到办法了吧?
解决方案:
1:如果网站数据少,小于2M是可以直接备份还原的;
2:如果数据较多备份文件过大,有两种方法解决,第一种是分段备份,在phpmyadmin的备份选项中设置为每个备份文件大小不超过2M,第二种是在还原空间的phpmyadmin中修改软件源文件进行设置,改为对还原文件没有大小限制,方法可以在网上搜索。
应该说此种备份方法相对麻烦,且需要自己购有服务器或vps,否则根本没有相关权限,一般情况下不建议选择。
三:直接在mysql文件夹中复制文件偷懒有隐患
部分有独立服务器而且偷懒的站长喜欢直接进入服务器的mysql文件夹下的DATA文件夹找到数据库文件复制后再粘贴到新空间。这样有个很大的弊端:备份的目标数据库如果正在使用的话你在进行复制,粘贴到新空间mysql文件夹后数据库会出现错误。
解决方法:我们不提倡这样搬迁数据库,可靠性不高。
四:通过网站程序自带功能进行备份还原网站显示连接错误?
现在使用到mysql数据库大家又都在广泛使用的网站程序有DZ,PW,DEDE等,这些程序后台都有备份还原功能,因为是自带的功能,兼容性好,方便快捷,1被大家广泛选择,但是新站长大多会遇到一个普遍问题:新的空间分配的数据库名和密码与原数据库资料根本不同,连网站程序后台都进不去,哪还谈的上还原呢?
解决方法:严格按照网站程序说明搬迁,可以重新安装网站程序,再进入后台选择还原已经保存的备份文件进行还原,目前所有的主流程序都提倡这种方法。
多线程程序一段有关问题代码分析(生产者消费者)
多线程程序一段问题代码分析(生产者消费者)
问题在《一个java生产者消费者代码的问题》,解答一下,只解释原因,其他不考虑。
作者要的是一个生产者生成,接着必须有一个消费者消费,那这不是需要单线程吗?或者使用1个大小的阻塞队列。所以只谈论问题本身,不谈论好不好。
具体代码:
import java.util.concurrent.locks.C
import java.util.concurrent.locks.L
import java.util.concurrent.locks.ReentrantL
//生产/消费者模式
public class Basket {
Lock lock = new ReentrantLock();
// 产生Condition对象
Condition produced = lock.newCondition();
Condition consumed = lock.newCondition();
boolean available =
public void produce() throws InterruptedException {
lock.lock();
if (available) {
produced.await(); // 放弃lock进入睡眠
System.out.println("Apple produced.");
available =
consumed.signal(); // 发信号唤醒等待这个Condition的线程
} finally {
lock.unlock();
public void consume() throws InterruptedException {
lock.lock();
if (!available) {
consumed.await(); // 放弃lock进入睡眠
/* 吃苹果 */
System.out.println("Apple consumed.");
available =
produced.signal(); // 发信号唤醒等待这个Condition的线程
} finally {
lock.unlock();
import java.util.concurrent.ExecutorS
import java.util.concurrent.E
//测试用类
public class ConditionTester {
public static void main(String[] args) throws InterruptedException {
final Basket basket = new Basket();
// 定义一个producer
Runnable producer = new Runnable() {
public void run() {
basket.produce();
} catch (InterruptedException ex) {
ex.printStackTrace();
// 定义一个consumer
Runnable consumer = new Runnable() {
public void run() {
basket.consume();
} catch (InterruptedException ex) {
ex.printStackTrace();
// 各产生10个consumer和producer
ExecutorService service = Executors.newCachedThreadPool();
for (int i = 0; i & 4; i++)
service.submit(consumer);
Thread.sleep(2000 * 2);
for (int i = 0; i & 4; i++)
service.submit(producer);
service.shutdown();
原因分析:
1、假设前面有2个producer(此时available=true)
1.1、一个在等待lock
1.2、一个await
2、consumer生成内容后,available=false,produced.signal(); 最后lock.unlock();
3.1、因为lock.unlock所以会触发一个lock获取到锁(虽然signal也会触发等待这个条件的其他线程,但是多线程大家都知道什么时候触发这是不确定的),如果此时正好是[1.1]那么因为available=false,执行完释放锁
3.2、produced.signal()所以会触发一个await的producer;
解决方案:
只要保证[3.1]还是需要await即可解决问题
所以加一个 AtomicInteger producedAwaitCounter = new AtomicInteger(0); 统计当前等待的生产者,如果当前available=false,但已经有生产者生成了内容,那么先等待消费者消费了再说
if (available || producedAwaitCounter.get() & 0) {
producedAwaitCounter.incrementAndGet();
produced.await(); // 放弃lock进入睡眠
producedAwaitCounter.decrementAndGet();
当然最简单的是使用:自旋,原理可以自己分析下:
while (available) {
produced.await(); // 放弃lock进入睡眠
package com.sishuok.es.
import java.util.concurrent.atomic.AtomicI
import java.util.concurrent.locks.C
import java.util.concurrent.locks.L
import java.util.concurrent.locks.ReentrantL
//生产/消费者模式
public class Basket {
Lock lock = new ReentrantLock(true);
// 产生Condition对象
Condition produced = lock.newCondition();
Condition consumed = lock.newCondition();
boolean available =
AtomicInteger producedAwaitCounter = new AtomicInteger(0);
public void produce() throws InterruptedException {
lock.lock();
if (available || producedAwaitCounter.get() & 0) {
producedAwaitCounter.incrementAndGet();
produced.await(); // 放弃lock进入睡眠
producedAwaitCounter.decrementAndGet();
System.out.println("Apple produced.");
available =
consumed.signal(); // 发信号唤醒等待这个Condition的线程
} finally {
lock.unlock();
public void consume() throws InterruptedException {
lock.lock();
if (!available) {
consumed.await(); // 放弃lock进入睡眠
/* 吃苹果 */
System.out.println("Apple consumed.");
available =
produced.signal(); // 发信号唤醒等待这个Condition的线程
} finally {
lock.unlock();
在回答里还一个类似的,不过还是不太一样。
http://blog.csdn.net/liguogangde/article/details/9103501
虽然consumer或者producer signal另外的线程之后,没法保证下一个获取锁的到底是consumer还是producer,但是available变量可以保证如果下一个获取锁的跟signal的那个是同样类型的(都是producer或者consumer),那么它会进入wait状态。
问题就处在available,如果是unlock后又一个lock的producer获取了,因为available=false,所以不会await,但是await的producer 已经判断过了,所以不会有问题;其实可以参考第二篇帖子;但是不一样的是此处不能再简单的if,否则不会进行System.out,造成一次丢失生产者生产的数据在await后,需要while 判断下available也能搞定。即自旋判断available直到其真正的获取到条件。即最简单的是使用:
while (available) {
produced.await(); // 放弃lock进入睡眠
也没有完全解决卡死的问题。必须要有两个counter呀,producer一个,consumer也要一个的。
很希望听详解,具体分析下。
teasp 写道
虽然consumer或者producer signal另外的线程之后,没法保证下一个获取锁的到底是consumer还是producer,但是available变量可以保证如果下一个获取锁的跟signal的那个是同样类型的(都是producer或者consumer),那么它会进入wait状态。
问题就处在available,如果是unlock后又一个lock的producer获取了,因为available=false,所以不会await,但是await的producer 已经判断过了,所以不会有问题;其实可以参考第二篇帖子;但是不一样的是此处不能再简单的if,否则不会进行System.out,造成一次丢失生产者生产的数据在await后,需要while 判断下available也能搞定。即自旋判断available直到其真正的获取到条件。即最简单的是使用:
while (available) {
produced.await(); // 放弃lock进入睡眠
你的说法有道理。
teasp 写道
也没有完全解决卡死的问题。必须要有两个counter呀,producer一个,consumer也要一个的。
很希望听详解,具体分析下。
跟你在producer上加counter是一样的道理呀。
可能是我表述不达意!我说的和你这个情况是一样的,只是解决方案略有不同!
是的。问题是出于一种情况。
对于卡死的说法,我得更正下,这是我分析错了,虽然两个producer会同时进入到await状态,但是consumer会将其中的一个唤醒。因此不会卡死。
正解,呵呵!这个程序光用看确实很容易犯错。特别还是看别人的代码!以后多一起讨论下!
teasp 写道
对于卡死的说法,我得更正下,这是我分析错了,虽然两个producer会同时进入到await状态,但是consumer会将其中的一个唤醒。因此不会卡死。
正解,呵呵!这个程序光用看确实很容易犯错。特别还是看别人的代码!以后多一起讨论下!
你是liguogang?
teasp 写道
对于卡死的说法,我得更正下,这是我分析错了,虽然两个producer会同时进入到await状态,但是consumer会将其中的一个唤醒。因此不会卡死。
正解,呵呵!这个程序光用看确实很容易犯错。特别还是看别人的代码!以后多一起讨论下!
你是liguogang?
teasp 写道
teasp 写道
对于卡死的说法,我得更正下,这是我分析错了,虽然两个producer会同时进入到await状态,但是consumer会将其中的一个唤醒。因此不会卡死。
正解,呵呵!这个程序光用看确实很容易犯错。特别还是看别人的代码!以后多一起讨论下!
你是liguogang?
李国刚,人物名。知名人物主要有洛阳市副市长,财经作家、联想管理模式研究专家等。
teasp 写道
teasp 写道
对于卡死的说法,我得更正下,这是我分析错了,虽然两个producer会同时进入到await状态,但是consumer会将其中的一个唤醒。因此不会卡死。
正解,呵呵!这个程序光用看确实很容易犯错。特别还是看别人的代码!以后多一起讨论下!
你是liguogang?
李国刚,人物名。知名人物主要有洛阳市副市长,财经作家、联想管理模式研究专家等。
我是最不知名那个,哈哈!
teasp 写道
teasp 写道
对于卡死的说法,我得更正下,这是我分析错了,虽然两个producer会同时进入到await状态,但是consumer会将其中的一个唤醒。因此不会卡死。
正解,呵呵!这个程序光用看确实很容易犯错。特别还是看别人的代码!以后多一起讨论下!
你是liguogang?
李国刚,人物名。知名人物主要有洛阳市副市长,财经作家、联想管理模式研究专家等。
jinnianshilongnian 写道
teasp 写道
teasp 写道
对于卡死的说法,我得更正下,这是我分析错了,虽然两个producer会同时进入到await状态,但是consumer会将其中的一个唤醒。因此不会卡死。
正解,呵呵!这个程序光用看确实很容易犯错。特别还是看别人的代码!以后多一起讨论下!
你是liguogang?
李国刚,人物名。知名人物主要有洛阳市副市长,财经作家、联想管理模式研究专家等。
开涛人气旺呀!帖子都上到首页了第一位了。给我的那篇博客都带去几十个人。牛x!
jinnianshilongnian 写道
teasp 写道
teasp 写道
对于卡死的说法,我得更正下,这是我分析错了,虽然两个producer会同时进入到await状态,但是consumer会将其中的一个唤醒。因此不会卡死。
正解,呵呵!这个程序光用看确实很容易犯错。特别还是看别人的代码!以后多一起讨论下!
你是liguogang?
李国刚,人物名。知名人物主要有洛阳市副市长,财经作家、联想管理模式研究专家等。
jinnianshilongnian 写道
teasp 写道
teasp 写道
对于卡死的说法,我得更正下,这是我分析错了,虽然两个producer会同时进入到await状态,但是consumer会将其中的一个唤醒。因此不会卡死。
正解,呵呵!这个程序光用看确实很容易犯错。特别还是看别人的代码!以后多一起讨论下!
你是liguogang?
李国刚,人物名。知名人物主要有洛阳市副市长,财经作家、联想管理模式研究专家等。
开涛人气旺呀!帖子都上到首页了第一位了。给我的那篇博客都带去几十个人。牛x!
哈哈,来iteye开博客啊,一起进步
jinnianshilongnian 写道
teasp 写道
teasp 写道
对于卡死的说法,我得更正下,这是我分析错了,虽然两个producer会同时进入到await状态,但是consumer会将其中的一个唤醒。因此不会卡死。
正解,呵呵!这个程序光用看确实很容易犯错。特别还是看别人的代码!以后多一起讨论下!
你是liguogang?
李国刚,人物名。知名人物主要有洛阳市副市长,财经作家、联想管理模式研究专家等。
jinnianshilongnian 写道
teasp 写道
teasp 写道
对于卡死的说法,我得更正下,这是我分析错了,虽然两个producer会同时进入到await状态,但是consumer会将其中的一个唤醒。因此不会卡死。
正解,呵呵!这个程序光用看确实很容易犯错。特别还是看别人的代码!以后多一起讨论下!
你是liguogang?
李国刚,人物名。知名人物主要有洛阳市副市长,财经作家、联想管理模式研究专家等。
开涛人气旺呀!帖子都上到首页了第一位了。给我的那篇博客都带去几十个人。牛x!
哈哈,来iteye开博客啊,一起进步
好,把博客移到iteye上来,多多指导!
如果您想提高自己的技术水平,欢迎加入本站官方1号QQ群:&&,&&2号QQ群:,在群里结识技术精英和交流技术^_^
本站联系邮箱:- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)
知识点:这个方法是单线程的,也就是说只有当前调用此方法的函数执行完毕后,selector方法才会被调用。
- (void)mainMethod
[self performSelector:@selector(delayMethod) withObject:nil afterDelay:1];
NSLog(@"调用方法==开始");
NSLog(@"调用方法==结束");
- (void)delayMethod
NSLog(@"执行延迟方法");
执行结果(注意log打印的顺序):
调用方法==开始
调用方法==结束
执行延迟方法
实战经验:正因为本方法是一个单线程的,所以有些时候,我们会遇到虽然调用了这个方法,但是不执行的问题。这时,我们需要将原代码改造如下:
改造前代码:无法执行延迟方法
-(void)someMethod
[self performSelector:@selector(labelDidDisappeared:) withObject:label afterDelay:2];
//因为某些原因,不被调用,没有执行
-(void)labelDidDisappeared:(UILabel *)label
[label removeFromSuperview];
[label release];
改造后代码: &可以正常执行延迟方法
-(void)someMethod
[self performSelectorOnMainThread:@selector(labelWillDisappeared:) withObject:label waitUntilDone:NO];
-(void)labelWillDisappeared:(UILabel *)label
[self performSelector:@selector(labelDidDisappeared:) withObject:label afterDelay:2];
-(void)labelDidDisappeared:(UILabel *)label
[label removeFromSuperview];
[label release];
&知识扩展:以下两个方法均是多线程方法
- (void)performSelectorInBackground:(SEL)aSelector withObject:(id)arg
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)
参考:& 感谢原作者的无私和奉献!
知识点:该方法只能接受一个参数。如果需要传递多个参数怎么办呢?&让selector调用的方法接受的参数类型修改为Dictionary类型。
(1)如果调用的selector不接受参数则,withObject:nil&
(2) 通过performSelector:withObjcet:afterDelay调用的方法不能有返回值
&知识扩展:performSelector 带多个参数
//第一个试验:带一个参数
- (void) fooOneIput:(NSString*) first {
NSLog(@"Logs %@", first);
//然后调用它
[self&performSelector:@selector(fooOneInput:) withObject:@"first"];
//第二个试验:带多个参数
- (void) fooFirstInput:(NSString*) first secondInput:(NSString*) second {
NSLog(@"Logs %@ then %@", first, second);
//然后调用它
[self&performSelector:@selector(fooFirstInput:secondInput:) withObject:@"first"&withObject:@"second"];
实战经验:经实验,只有performSelector: withObject: 方法可以带多个参数,其它类似的perform方法均不行,包括和此方法最类似的performSelectorInBackground:withObject: 方法。
延伸阅读:
阅读(...) 评论()7810人阅读
前几天在给游戏做收尾测试时,发现了一个关于内存泄露的问题,一直没找着问题所在,经过反复调试和查找资料今天终于解决了,特此记录下来以免以后再犯!
关于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: ,否则有可能产生内存泄露,而且这种内存泄露很难发现,因为它并不违反任何规则,所以一定要注意!
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:815738次
积分:9567
积分:9567
排名:第1088名
原创:125篇
评论:481条
NAME:FCPlayer
CITY:Beijing
Degree:Master
Skills:Java、IOS、.NET
文章:11篇
阅读:68722
(1)(1)(1)(1)(2)(2)(1)(1)(1)(2)(1)(1)(1)(1)(1)(3)(5)(6)(1)(5)(5)(5)(4)(2)(8)(5)(5)(8)(14)(16)(5)(5)(5)(3)(2)(1)(2)(3)

我要回帖

更多关于 performselector 的文章

 

随机推荐