代码改变世界

IOS - 延迟执行performSelector和取消延迟执行cancelPreviousPerformRequestsWithTarget

2015-08-18 21:58  HermitCarb  阅读(7452)  评论(0编辑  收藏  举报

IOS开发时可能会想用到延时执行一个函数。学会用这个函数有时会让代码简单很多。

下文出现的self均指当前页面控制器(ViewController)

基本方法:

 1 @interface NSObject (NSDelayedPerforming)
 2 
 3 //设置延迟执行,delay单位为秒
 4 - (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay inModes:(NSArray *)modes;
 5 
 6 - (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay;
 7 
 8 //取消已设置的延迟执行
 9 + (void)cancelPreviousPerformRequestsWithTarget:(id)aTarget selector:(SEL)aSelector object:(id)anArgument;
10 
11 + (void)cancelPreviousPerformRequestsWithTarget:(id)aTarget;
12 
13 @end

 

如若设置下面的延迟执行方法:

1 [self performSelector:@selector(didRuninCurrModel:) withObject:[NSNumber numberWithBool:YES] afterDelay:3.0f];
2 
3 [self performSelector:@selector(didRuninCurrModelNoArgument) withObject:nil afterDelay:3.0f];

 

若取消对应的延迟执行方法可用下面方法:

1 [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(didRuninCurrModel:) object:[NSNumber numberWithBool:YES]];
2 
3 [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(didRuninCurrModelNoArgument) object:nil];

 

需要注意的是参数的一致性,如下面的取消无法实现:

1 [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(didRuninCurrModel:) object:[NSNumber numberWithBool:NO]];
2 
3 [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(didRuninCurrModel:) object:nil];

 

下面方法可以一次取消所有的延迟执行:

1 [NSObject cancelPreviousPerformRequestsWithTarget:self];
2 
3 [[self class] cancelPreviousPerformRequestsWithTarget:self];

 

注意:设置延迟执行可能会导致内存泄漏:

(这个我也不是特别懂,不能说没遇到过,只是现在的水平还达不到那个高度)

搜集网上的资料说:当页面需要dealloc时,若延迟函数还没有执行会引发内存泄漏。

个人认为如果像这样设置延迟执行:

1 [self performSelector:@selector(function) withObject:self afterDelay:30.0f];

若在页面需要dealloc时没有执行延迟函数,从self的引用计数来看应该会出现内存泄漏。

但是不清楚当参数withObject:nil 时会不会改变self的引用计数。

 

另外,我在一次练习中用到了这个延迟执行,但是,最终失败了,分享一下我当时的做法和现在的一些想法。

TestApp是一个NavigationController控制的二级页面。当点击首页的TableViewCell会跳转到第二级页面。然后我的延迟执行是在第二级页面设置的。延迟执行设置和执行方面正常,但当我设置好延迟执行,返回主页然后再进入该第二级页面,无法取消之前设置的延迟执行。

 

NavigationController控制的页面跳转,是把页面控制器放到一个栈里,根据前进还是返回进行入栈和出栈的。后来分析了下,像上面,我第二次进入第二级页面已经不是第一次进入的那个第二级页面了,所以不能取消第一次设置的延迟执行。但是延迟执行能够执行成功,则是说明第一次的那个第二级页面虽然出栈了但没有被dealloc掉,这个应该是因为设置延迟执行会增加页面的引用计数,而和设置引用计数时有没有设置withObject:self 或者withObject:nil 没有关系。

 

不知道我的想法对不对,大神不要嘲笑,欢迎指导!