1.不知道大家有没有注意,为什么NSTImer的property里是weak的?
首先,介绍一下单次定时和循环定时:
//创建一个类
@interface TestObj :NSObject
- (void)timerAct;
@end
@implementation TestObj
- (id)init
{
self = [superinit];
NSLog(@"Obj has been created!");;
return self;
}
- (void)timerAct
{
NSLog(@"timer is executing!");
}
- (void)dealloc
{
NSLog(@"Obj has been dealloced!!");
//[super dealloc];
}
@end
- (void)viewDidLoad
{
[superviewDidLoad];
[selfnonRepeatTimer];
[selfRepeatTimer];
}
- (void)nonRepeatTimer//只执行一次的Timer
{
NSLog(@"timer is nonRepeatTimer!");
TestObj *test = [[TestObjalloc]init];
[NSTimerscheduledTimerWithTimeInterval:5target:test selector:@selector(timerAct)userInfo:NULLrepeats:NO];
//[test release];
NSLog(@"Invoke release to testObject");
}
- (void)RepeatTimer//循环执行的Timer
{
NSLog(@"timer is RepeatTimer!");
TestObj *test = [[TestObjalloc]init];
[NSTimerscheduledTimerWithTimeInterval:5target:test selector:@selector(timerAct)userInfo:NULLrepeats:YES];
//[test release];
NSLog(@"Invoke release to testObject");
}
执行一次Timer时的结果
2014-09-19 15:23:16.765 TEST[1760:60b] timer is nonRepeatTimer!
2014-09-19 15:23:16.767 TEST[1760:60b] Obj has been created!
2014-09-19 15:23:16.768 TEST[1760:60b] Invoke release to testObject
2014-09-19 15:23:21.769 TEST[1760:60b] timer is executing!
2014-09-19 15:23:21.770 TEST[1760:60b] Obj has been
执行循环Timer时的结果
2014-09-19 15:25:45.057 TEST[1777:60b] timer is RepeatTimer!
2014-09-19 15:25:45.059 TEST[1777:60b] Obj has been created!
2014-09-19 15:25:45.059 TEST[1777:60b] Invoke release to testObject
2014-09-19 15:25:50.060 TEST[1777:60b] timer is executing!
2014-09-19 15:25:55.060 TEST[1777:60b] timer is executing!
而NSTimer的属性之所以为weak,原因真是在此:如果timer循环触发时,对象一直retain,那么将无法被创建它的类释放,因为timer使它的引用计数又加了1.
2.NSTimer是不是一定准时触发事件?
答案使否定的,当NSTimer被设置以后,会被丢到runloop中,达到触发时间时,如果此时runloop空闲就会立即执行;但是如果此时runloop正忙,则需要在触发时间的基础上等到runloop空闲再去执行。
3.为什么要把NSTimer添加到runloop才有用?
首先测试如果不放入runloop时:
- (void)viewDidLoad
{
[superviewDidLoad];
//[self nonRepeatTimer];
//[self RepeatTimer];
[selfnotPutInRunloop];
}
- (void)notPutInRunloop
{
NSLog(@"timer don't put in runloop");
NSTimer *timer = [[NSTimeralloc] initWithFireDate:[[NSDate alloc] initWithTimeIntervalSinceNow:5]interval:5target:selfselector:@selector(timerAct)userInfo:NULLrepeats:NO];//初始化一个新的NSTimer
NSLog(@"Invoke release to testObject");
}
输出结果:
2014-09-19 16:34:06.005 TEST[2347:60b] timer don't put in runloop
2014-09-19 16:34:06.007 TEST[2347:60b] Obj has been created!
2014-09-19 16:34:06.008 TEST[2347:60b] Invoke release to testObject
2014-09-19 16:34:06.008 TEST[2347:60b] Obj has been dealloced!!
说明timer根本没有触发,因为这个次没有把timer放到runloop上。
4.如何把NSTimer添加到runloop中?
- (void)viewDidLoad
{
[superviewDidLoad];
//[self nonRepeatTimer];
//[self RepeatTimer];
//[self notPutInRunloop];
[NSThreaddetachNewThreadSelector:@selector(PutInRunloop)toTarget:selfwithObject:nil];//直接创建线程并运行,selector:线程执行的方法,target:selector消息发送的对象
}
- (void)PutInRunloop
{
NSLog(@"timer put in runloop");
TestObj *test = [[TestObjalloc]init];
NSTimer *timer = [[NSTimeralloc] initWithFireDate:[[NSDatealloc] initWithTimeIntervalSinceNow:5]interval:5target:selfselector:@selector(timerAct)userInfo:NULLrepeats:NO];
[[NSRunLoopcurrentRunLoop] addTimer:timerforMode:NSDefaultRunLoopMode];
NSLog(@"Invoke release to testObject");
}
输出的结果:
2014-09-19 16:28:36.480 TEST[2227:3307] timer put in runloop
2014-09-19 16:28:36.483 TEST[2227:3307] Obj has been created!
2014-09-19 16:28:36.485 TEST[2227:3307] Invoke release to testObject
2014-09-19 16:28:36.486 TEST[2227:3307] Obj has been dealloced!!
还是没有执行方法,why?
- (void)PutInRunloop
{
NSLog(@"timer put in runloop");
TestObj *test = [[TestObjalloc]init];
NSTimer *timer = [[NSTimeralloc] initWithFireDate:[[NSDatealloc] initWithTimeIntervalSinceNow:5]interval:1target:test selector:@selector(timerAct)userInfo:NULLrepeats:NO];
[[NSRunLoopcurrentRunLoop] addTimer:timerforMode:NSDefaultRunLoopMode];
[[NSRunLoopcurrentRunLoop] runUntilDate:[NSDatedateWithTimeIntervalSinceNow:5]]; //这里的NSData参数必须大于上面NSTimer初始化时开始的时间
NSLog(@"Invoke release to testObject");
}
是因为[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:5]]没有加,这个代表该runloop将会在5秒以后结束;
通过子线程调用selector时,子线程是不会默认启动的,必须加上runUntilDate 方法。